From a82556379caadef548ce8978d404d0e3ece5446c Mon Sep 17 00:00:00 2001 From: Gerard van Dongen Date: Sat, 18 Oct 2003 13:38:48 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r1106, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/ff/; revision=1107 --- ff/GnuGPL.txt | 290 ++++++++++ ff/README | 19 + ff/TODO | 13 + ff/ff-autocenter.pd | 9 + ff/ff-constant.pd | 39 ++ ff/ff-gain.pd | 8 + ff/ff-periodic.pd | 44 ++ ff/ff-spring.pd | 65 +++ ff/ff.c | 1526 +++++++++++++++++++++++++++++++++++++++++++++++++++ ff/input.h | 831 ++++++++++++++++++++++++++++ ff/makefile | 7 + ff/multi.pd | 23 + 12 files changed, 2874 insertions(+) create mode 100644 ff/GnuGPL.txt create mode 100644 ff/README create mode 100644 ff/TODO create mode 100644 ff/ff-autocenter.pd create mode 100644 ff/ff-constant.pd create mode 100644 ff/ff-gain.pd create mode 100644 ff/ff-periodic.pd create mode 100644 ff/ff-spring.pd create mode 100644 ff/ff.c create mode 100644 ff/input.h create mode 100644 ff/makefile create mode 100644 ff/multi.pd diff --git a/ff/GnuGPL.txt b/ff/GnuGPL.txt new file mode 100644 index 0000000..fa0bef4 --- /dev/null +++ b/ff/GnuGPL.txt @@ -0,0 +1,290 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This General +Public License applies to most of the Free Software Foundation's +software and to any other program whose authors commit to using it. +(Some other Free Software Foundation software is covered by the +GNU Library General Public License instead.) You can apply it to your +programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone +to deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you distribute +copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis +or for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And +you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software patents. +We wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent must +be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR +COPYING, DISTRIBUTION AND +MODIFICATION + +0. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed under +the terms of this General Public License. The "Program", below, refers +to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, either +verbatim or with modifications and/or translated into another language. +(Hereinafter, translation is included without limitation in the term +"modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +the Program is not restricted, and the output from the Program is +covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether +that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the notices +that refer to this License and to the absence of any warranty; and give +any other recipients of the Program a copy of this License along with the +Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, and +can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based on +the Program, the distribution of the whole must be on the terms of this +License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based +on the Program. + +In addition, mere aggregation of another work not based on the +Program with the Program (or with a work based on the Program) on a +volume of a storage or distribution medium does not bring the other +work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding + machine-readable source code, which must be distributed under + the terms of Sections 1 and 2 above on a medium customarily + used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your cost + of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with + such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies the +executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy +the source code from the same place counts as distribution of the source +code, even though third parties are not compelled to copy the source +along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full +compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and all +its terms and conditions for copying, distributing or modifying the +Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these terms +and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. You are not responsible +for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot distribute +so as to satisfy simultaneously your obligations under this License and +any other pertinent obligations, then as a consequence you may not +distribute the Program at all. For example, if a patent license would not +permit royalty-free redistribution of the Program by all those who +receive copies directly or indirectly through you, then the only way you +could satisfy both it and this License would be to refrain entirely from +distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system, which is implemented by public license +practices. Many people have made generous contributions to the wide +range of software distributed through that system in reliance on +consistent application of that system; it is up to the author/donor to +decide if he or she is willing to distribute software through any other +system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be +a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an +explicit geographical distribution limitation excluding those countries, so +that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number +of this License, you may choose any version ever published by the Free +Software Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF +CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, +TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD +THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE +COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW +OR AGREED TO IN WRITING WILL ANY COPYRIGHT +HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED +ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING +ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT +LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR +OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY +OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS diff --git a/ff/README b/ff/README new file mode 100644 index 0000000..628fae0 --- /dev/null +++ b/ff/README @@ -0,0 +1,19 @@ +This is a small library that implements force feedback effects for pd. +It is BETA. +I might completely change this (see the TODO) +To compile: +make sure that m_pd.h is in your include path + +patch your kernel with ff-patches from Johann Deneux: +--( http://user.it.uu.se/~johannd/projects/ff/index.shtml) + +He also has a standalone iforce driver available + + +type make. +Manually install everything :) + +have fun + +Gerard van Dongen +gml@xs4all.nl diff --git a/ff/TODO b/ff/TODO new file mode 100644 index 0000000..5c755d0 --- /dev/null +++ b/ff/TODO @@ -0,0 +1,13 @@ + +-add user definable waveforms for the periodic effects. + +-unify all externals into a single forcefeedback external? + +I am not sure if this is a good idea.It will make the code +cleaner because it is closer to the hardware model, and it +would allow intergration with the joystick object. +But it will make patching more cumbersome. + +-more testing with other iforce compatible devices +-add rumble,ramp,damper and inertia effects. +-learn autotools and autotoolize this. \ No newline at end of file diff --git a/ff/ff-autocenter.pd b/ff/ff-autocenter.pd new file mode 100644 index 0000000..323afd8 --- /dev/null +++ b/ff/ff-autocenter.pd @@ -0,0 +1,9 @@ +#N canvas 393 404 450 300 10; +#X text 30 34 sets the amount of "autocentering" of the force-feedback +joystick. Range is [0 \, 1]. 0 is no auto-centering; +#X msg 48 141 0.5; +#X obj 48 191 ff-autocenter 0 0; +#X text 29 69 creation arguments are the device number (starting at +0) and autocenter amount. This affects all effects for that device +; +#X connect 1 0 2 0; diff --git a/ff/ff-constant.pd b/ff/ff-constant.pd new file mode 100644 index 0000000..48a8fb7 --- /dev/null +++ b/ff/ff-constant.pd @@ -0,0 +1,39 @@ +#N canvas 161 237 742 413 10; +#X msg 68 150 bang; +#X msg 44 213 stop; +#X floatatom 301 269 5 0 0 0 - - -; +#X floatatom 187 214 5 0 0 0 - - -; +#X text 185 196 direction in degrees; +#X floatatom 244 249 5 0 0 0 - - -; +#X text 340 264 level \, range = [-1 \, 1]; +#X text 7 130 start the effect; +#X text 12 146 with a; +#X msg 131 77 delay 250; +#X msg 131 48 interval 500; +#X text 229 79 delay before starting; +#X text 229 50 minimum time between triggers; +#X obj 131 290 ff-constant 0 45 1000 0.5; +#X text 107 314 arguments are inputdevice-number \, direction \, duration +and level; +#X msg 131 151 load; +#X msg 131 175 unload; +#X text 191 150 a load message \, uploads an effect to the stick; +#X text 190 175 an unload message \, removes it; +#X text 303 110 startlevel attack-duration (ms) endlevel decay-duration +; +#X msg 131 112 envelope 0 500 0.5 100; +#X text 300 125 levels are in the range [0 \, 1].; +#X text 109 352 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X text 241 221 duration in ms \, 0 is infinite \, this includes the +attack/decay times; +#X connect 0 0 13 0; +#X connect 1 0 13 0; +#X connect 2 0 13 3; +#X connect 3 0 13 1; +#X connect 5 0 13 2; +#X connect 9 0 13 0; +#X connect 10 0 13 0; +#X connect 15 0 13 0; +#X connect 16 0 13 0; +#X connect 20 0 13 0; diff --git a/ff/ff-gain.pd b/ff/ff-gain.pd new file mode 100644 index 0000000..94b1008 --- /dev/null +++ b/ff/ff-gain.pd @@ -0,0 +1,8 @@ +#N canvas 0 0 450 300 10; +#X text 26 62 sets the overall gain [0 \, 1] of the force-feedback +joystick on the device.; +#X msg 74 182 0.3; +#X obj 74 222 ff-gain 0 0.5; +#X text 24 105 creation arguments are the device-number (starting at +0) and gain. This effects all effects for that device; +#X connect 1 0 2 0; diff --git a/ff/ff-periodic.pd b/ff/ff-periodic.pd new file mode 100644 index 0000000..f280692 --- /dev/null +++ b/ff/ff-periodic.pd @@ -0,0 +1,44 @@ +#N canvas 155 183 711 418 10; +#X msg 27 211 bang; +#X msg 3 274 stop; +#X floatatom 340 294 5 0 0 0 - - -; +#X msg 87 12 waveform sine; +#X msg 87 35 period 400; +#X msg 87 86 phase 90; +#X msg 87 60 offset 0.25; +#X text 192 13 square|sine|triangle|saw_up|saw_down; +#X text 192 35 period time in ms (defaults 1000 ms); +#X text 194 59 waveform offset from center [-1 \, 1] (defaults 0=centered) +; +#X floatatom 169 234 5 0 0 0 - - -; +#X text 164 210 direction in degrees; +#X floatatom 257 263 5 0 0 0 - - -; +#X text 338 274 level \, range = [-1 \, 1]; +#X text 255 89 waveform phase in degrees; +#X text -34 191 start the effect; +#X text -29 207 with a; +#X msg 87 139 delay 250; +#X msg 87 113 interval 500; +#X text 255 143 delay before starting; +#X text 257 114 minimum time between triggers; +#X obj 87 329 ff-periodic 0 0 0 0.5; +#X text 90 354 arguments are device-number \, duration and level; +#X msg 87 168 envelope 0 1000 0 100; +#X text 259 160 startlevel attack-duration endlevel decay-duration +levels or in the range [0 \, 1]; +#X text 254 226 duration in ms \, 0 is infinite \, this includes the +attack/decay times; +#X text 90 370 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X connect 0 0 21 0; +#X connect 1 0 21 0; +#X connect 2 0 21 3; +#X connect 3 0 21 0; +#X connect 4 0 21 0; +#X connect 5 0 21 0; +#X connect 6 0 21 0; +#X connect 10 0 21 1; +#X connect 12 0 21 2; +#X connect 17 0 21 0; +#X connect 18 0 21 0; +#X connect 23 0 21 0; diff --git a/ff/ff-spring.pd b/ff/ff-spring.pd new file mode 100644 index 0000000..980ff2c --- /dev/null +++ b/ff/ff-spring.pd @@ -0,0 +1,65 @@ +#N canvas 173 83 685 588 10; +#X msg 46 262 bang; +#X msg 102 261 stop; +#X text 39 242 with a; +#X msg 141 129 delay 250; +#X msg 141 104 interval 500; +#X text 275 130 delay before starting; +#X text 239 104 minimum time between triggers; +#X text 292 192 coefficients that determine how fast; +#X text 292 204 the effect increases in that direction; +#X text 292 215 range = [-1 \, 1]; +#X text 261 279 width of the dead-zone \, where there is no effect +; +#X text 261 303 range is (like the joystick output) [-32768 \, 32767] +; +#X text 262 290 one for each axis; +#X text 262 332 position of the dead-zone in the joystick range; +#X text 262 344 one for each axis; +#X text 262 356 range is also [-32768 \, 32767]; +#X floatatom 204 411 5 0 0 0 - - -; +#X floatatom 331 458 5 0 0 0 - - -; +#X floatatom 267 458 5 0 0 0 - - -; +#X text 200 388 duration in ms \, 0 is infinite; +#X floatatom 394 458 5 0 0 0 - - -; +#X floatatom 458 461 5 0 0 0 - - -; +#X text 267 422 levels \, range = [0 \, 1]; +#X text 266 439 right; +#X text 332 438 left; +#X text 392 438 up; +#X text 458 439 down; +#X text 34 229 start; +#X text 4 79 ff-friction has the same methods; +#X text 5 33 ff-spring is a "conditional effect".; +#X obj 141 484 ff-spring 0 2000 0.5 0.5 0 0.1; +#X text 141 507 creation arguments are device-number \, duration right- +\, left- \, up- and down-level; +#X msg 141 281 deadband-x 1200; +#X msg 141 306 deadband-y 300; +#X msg 141 335 center-x 0; +#X msg 141 358 center-y 20000; +#X msg 141 195 left-coeff 1; +#X msg 141 173 right-coeff 1; +#X msg 141 219 up-coeff -0.7; +#X msg 141 242 down-coeff -1; +#X text 6 49 these effects set up 2 axes (x and y) and you specify +the parameters for each direction.; +#X text 139 540 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X connect 0 0 30 0; +#X connect 1 0 30 0; +#X connect 3 0 30 0; +#X connect 4 0 30 0; +#X connect 16 0 30 1; +#X connect 17 0 30 3; +#X connect 18 0 30 2; +#X connect 20 0 30 4; +#X connect 21 0 30 5; +#X connect 32 0 30 0; +#X connect 33 0 30 0; +#X connect 34 0 30 0; +#X connect 35 0 30 0; +#X connect 36 0 30 0; +#X connect 37 0 30 0; +#X connect 38 0 30 0; +#X connect 39 0 30 0; diff --git a/ff/ff.c b/ff/ff.c new file mode 100644 index 0000000..784b2fe --- /dev/null +++ b/ff/ff.c @@ -0,0 +1,1526 @@ +/* forcefeedback externals for linux pd + * copyright 2003 Gerard van Dongen gml@xs4all.nl + +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + * the api is unstable. read the README for details. + + * objects: + * ff-constant [device direction duration level ] + * ff-periodic [device direction duration level ] + * ff-spring [device duration right-levelx left-level-x right-levely left-level-y] + * ff-friction [device duration right-levelx left-level-x right-levely left-level-y] + + * additional methods for all objects: + * bang :starts + * stop :stops an effect + * delay :sets the delay before the effect is activated + * interval :sets the time to wait before an effect can be re-activated + + * methods for periodic effects + * waveform : square|triangle|sine|saw_up|saw_down + * period : period time in ms + * offset : + * phase : + * + * methods for constant and periodic effects: + * envelope : start-level attack end-level decay + * + * methods for spring and friction effects: + * right-coeff : + * left-coeff : + * deadband : + * center : + * + */ + + + + +#include "m_pd.h" + +#include +#include +#include +#include +#include +#include "input.h" + + + +#define FF_DEVICE "/dev/input/event0" + +#define BITS_PER_LONG (sizeof(long) * 8) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + + +static t_class *ffConstant_class; +static t_class *ffPeriodic_class; +static t_class *ffFriction_class; +static t_class *ffSpring_class; +static t_class *ffGain_class; +static t_class *ffAutocenter_class; + + +typedef struct _ff_device { + char name[64]; + int max_fx; + int loaded_fx; +} t_ff_device; + +static t_ff_device ff_dev[4]; + + + + +typedef struct _ff { + t_object x_obj; + int ff_fd; + struct ff_effect effects; + struct input_event do_that; + unsigned int device; +} t_ff; + + +struct _waveshapes { + char* wave; + unsigned short number; + } waves[]={{"square",FF_SQUARE}, + {"triangle",FF_TRIANGLE}, + {"sine",FF_SINE}, + {"saw_up",FF_SAW_UP}, + {"saw_down",FF_SAW_DOWN}, + {NULL,0}}; + +/******************************************************************************************************** + +general ff methods + +*********************************************************************************************************/ + +void ff_bang(t_ff *x) +{ + if (x->ff_fd < 0) return; + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + x->do_that.type = EV_FF; + x->do_that.code = x->effects.id; + x->do_that.value = 1; + + if (write(x->ff_fd, (const void*) &x->do_that, sizeof(x->do_that)) == -1) { + perror("Play effect error"); + } + outlet_float(x->x_obj.ob_outlet, (t_float) x->effects.id); +} + +void ff_stop(t_ff *x) +{ + + if (x->ff_fd < 0) return; + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + /* is it still playing ? */ + + x->do_that.type = EV_FF_STATUS; + x->do_that.code = x->effects.id; + + if ((read(x->ff_fd, (void *) &x->do_that, sizeof(x->do_that))) == -1) { + perror("couldn't read status of effect"); + } + + if (x->do_that.value = FF_STATUS_PLAYING) { + + x->do_that.type = EV_FF; + x->do_that.code = x->effects.id; + x->do_that.value = 0; + + if ((write(x->ff_fd, (const void*) &x->do_that, sizeof(x->do_that))) == -1) { + perror("Stop effect error"); + } + } +} + +void ff_delay(t_ff *x, t_floatarg delay) +{ + if (x->ff_fd < 0) return; + x->effects.replay.delay = (unsigned short) delay; + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } +} + +void ff_interval(t_ff *x, t_floatarg interval) +{ + if (x->ff_fd < 0) return; + x->effects.trigger.interval = (unsigned short) interval; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } +} + + + +void ff_duration(t_ff *x, t_floatarg duration ) +{ + if (x->ff_fd < 0) return; + + x->effects.replay.length = (unsigned short) duration; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } +} + +void ff_direction(t_ff *x, t_floatarg direction) +{ + if (x->ff_fd < 0) return; + unsigned short shortdirection; + shortdirection = (unsigned short)(direction * 182.044444); /*map degrees to 0-0xFFFF */ + + x->effects.direction = shortdirection; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + error("Upload effects error"); + } +} + +void ff_unload(t_ff *x) +{ + + if (x->ff_fd < 0) return; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + ff_stop(x); + + /* delete effect from the stick */ + if (ioctl(x->ff_fd, EVIOCRMFF, x->effects.id) == -1) { + perror("deleting effect"); + return; + } + + x->effects.id = -1; + ff_dev[x->device].loaded_fx = (ff_dev[x->device].loaded_fx == 0 ? 0 : --ff_dev[x->device].loaded_fx); + outlet_float(x->x_obj.ob_outlet, (t_float) x->effects.id); + +} + +void ff_load(t_ff *x) +{ + + if (x->ff_fd < 0) return; + if (x->effects.id != -1) { + post("effect is allready loaded"); + return; + } + + if (ff_dev[x->device].loaded_fx == ff_dev[x->device].max_fx) { + post("maximum number of fx is loaded, you have to unload one first"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + return; + } + ff_dev[x->device].loaded_fx++; + outlet_float(x->x_obj.ob_outlet, (t_float) x->effects.id); +} + +void ff_free(t_ff *x) +{ + + if (x->ff_fd < 0) return; + + if (x->effects.id != -1) { + + /* stop effect */ + ff_stop(x); + + /* delete effect from the stick */ + ff_unload(x); + } + + /* close device */ + + close(x->ff_fd); + +} + + + + + +/******************************************************************************************************** + +ff-constant methods + +*********************************************************************************************************/ + + +void ffConstant_level(t_ff *x, t_floatarg level) +{ + if (x->ff_fd < 0) return; + + short shortlevel; + level = (level > 1 ? 1:level); + level = (level < -1 ? -1:level); + shortlevel = (short) (level * 32767 ); /*map level -1 to 1 to signed short range */ + + x->effects.u.constant.level = shortlevel; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("level update error:"); + } +} + + +void ffConstant_envelope(t_ff *x, t_floatarg startlevel, t_floatarg startduration, t_floatarg endlevel, t_floatarg endduration) +{ + if (x->ff_fd < 0) return; + unsigned short shortattack,shortdecay; + startlevel = (startlevel > 1 ? 1:startlevel); + startlevel = (startlevel < 0 ? 0:startlevel); + endlevel = (endlevel > 1 ? 1:endlevel); + endlevel = (endlevel < 0 ? 0:endlevel); + shortattack = (unsigned short) (startlevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + shortdecay = (unsigned short) (endlevel * 65534); + x->effects.u.constant.envelope.attack_level = shortattack; + x->effects.u.constant.envelope.fade_level = shortdecay; + x->effects.u.constant.envelope.attack_length = (unsigned short) startduration; + x->effects.u.constant.envelope.fade_length = (unsigned short) endduration; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + +} + + +void *ffConstant_new(t_floatarg device,t_floatarg direction,t_floatarg duration, t_floatarg level) +{ + + unsigned short shortdirection,shortduration; + short shortlevel; + unsigned long features[4]; + int device_number; + + t_ff *x = (t_ff *)pd_new(ffConstant_class); + + device = (device > 4 ? 4:device); + device_number= (int)(device < 0 ? 0:device); + + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("direction")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("duration")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("level")); + + outlet_new(&x->x_obj, &s_float); + + if ((x->ff_fd=open((char *) ff_dev[device_number].name, O_RDWR | O_NONBLOCK)) < 0) { + error("ff-lib:couldn't open %s, no effect will happen",ff_dev[device_number].name); + return (void *) x; + } + + if ((ioctl(x->ff_fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)) == -1) { + perror("\nCouldn't determine available ff-effects \n FF probably won't work"); + close(x->ff_fd); + return (void *) x; + } + + if (!test_bit(FF_CONSTANT, features)) { + error("Constant force effect doesn't seem to be supported\n" + "the external won't do anything"); + close(x->ff_fd); + x->ff_fd = -1; + return (void *) x; + } + + + shortdirection = (unsigned short)(direction * 182.044444); /*map degrees to 0-0xFFFF */ + shortduration = (unsigned short) duration; + level = (level > 1 ? 1:level); + level = (level < -1 ? -1:level); + shortlevel = (short) (level * 32767 ); /*map level -1 to 1 to signed short range */ + + x->effects.type = FF_CONSTANT; + x->effects.id = -1; + x->effects.direction = shortdirection; + x->effects.u.constant.level =shortlevel; + x->effects.u.constant.envelope.attack_length = 0x000; + x->effects.u.constant.envelope.attack_level = 0; + x->effects.u.constant.envelope.fade_length = 0x000; + x->effects.u.constant.envelope.fade_level = 0; + x->effects.trigger.button = 0; + x->effects.trigger.interval = 0; + x->effects.replay.length =shortduration; + x->effects.replay.delay = 0; + x->device = device_number; + ff_load(x); + return (void*)x; +} + + + +/******************************************************************************************************** + +ff-periodic methods + +*********************************************************************************************************/ + + + + +void ffPeriodic_level(t_ff *x, t_floatarg level) +{ + if (x->ff_fd < 0) return; + short shortlevel; + level = (level > 1 ? 1:level); + level = (level < -1 ? -1:level); + shortlevel = (short) (level * 32767 ); /*map level -1 to 1 to signed short range */ + x->effects.u.periodic.magnitude = shortlevel; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } +} + + +void ffPeriodic_waveform(t_ff *x, t_symbol* waveform) +{ + if (x->ff_fd < 0) return; + unsigned short shortwave; + int n = 0; + + while (waves[n].wave) { + if (strcmp( waveform->s_name,waves[n].wave)) shortwave = waves[n].number; + n++; + } + + x->effects.u.periodic.waveform = shortwave; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + +} + +void ffPeriodic_period(t_ff *x, t_floatarg period) +{ + if (x->ff_fd < 0) return; + x->effects.u.periodic.period = (unsigned short) period; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } +} + +void ffPeriodic_offset(t_ff *x, t_floatarg offset) +{ + if (x->ff_fd < 0) return; + short shortoffset; + offset = (offset > 1 ? 1:offset); + offset = (offset < -1 ? -1:offset); + shortoffset = (short) (offset * 32767 ); /*map level -1 to 1 to signed short range */ + x->effects.u.periodic.offset = shortoffset; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } +} + +void ffPeriodic_phase(t_ff *x, t_floatarg phase) +{ + if (x->ff_fd < 0) return; + unsigned short shortphase; + shortphase = (unsigned short)(phase * 182.044444); /*map degrees to 0-0xFFFF */ + x->effects.u.periodic.phase = shortphase; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + error("Upload effects error"); + } + +} + +void ffPeriodic_envelope(t_ff *x, t_floatarg startlevel, t_floatarg startduration, t_floatarg endlevel, t_floatarg endduration) +{ + if (x->ff_fd < 0) return; + unsigned short shortattack,shortdecay; + startlevel = (startlevel > 1 ? 1:startlevel); + startlevel = (startlevel < 0 ? 0:startlevel); + endlevel = (endlevel > 1 ? 1:endlevel); + endlevel = (endlevel < 0 ? 0:endlevel); + shortattack = (unsigned short) (startlevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + shortdecay = (unsigned short) (endlevel * 65534); + x->effects.u.periodic.envelope.attack_level = shortattack; + x->effects.u.periodic.envelope.fade_level = shortdecay; + x->effects.u.periodic.envelope.attack_length = (unsigned short) startduration; + x->effects.u.periodic.envelope.fade_length = (unsigned short) endduration; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + +} + + + + +void *ffPeriodic_new(t_floatarg device,t_floatarg direction,t_floatarg duration, t_floatarg level) +{ + unsigned short shortdirection,shortduration; + short shortlevel; + unsigned long features[4]; + int device_number; + + t_ff *x = (t_ff *)pd_new(ffPeriodic_class); + + device = (device > 4 ? 4:device); + device_number= (int)(device < 0 ? 0:device); + + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("direction")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("duration")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("level")); + + outlet_new(&x->x_obj, &s_float); + + if ((x->ff_fd=open((char *) ff_dev[device_number].name, O_RDWR | O_NONBLOCK)) < 0 ){ + error("ff-lib:couldn't open %s, no effect will happen",ff_dev[device_number].name); + return (void *) x; + } + + if ((ioctl(x->ff_fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)) == -1) { + error("Couldn't determine available ff-effects \n FF probably won't work"); + close(x->ff_fd); + return (void *) x; + } + + if (!test_bit(FF_PERIODIC, features)) { + error("Periodic effect doesn't seem to be supported\n" + "the external won't do anything"); + close(x->ff_fd); + x->ff_fd = -1; + return (void *) x; + } + + shortdirection = (unsigned short)(direction * 182.044444); /*map degrees to 0-0xFFFF */ + shortduration = (unsigned short) duration; + level = (level > 1 ? 1:level); + level = (level < -1 ? -1:level); + shortlevel = (short) (level * 32767 ); /*map level -1 to 1 to signed short range */ + + x->effects.type = FF_PERIODIC; + x->effects.id = -1; + x->effects.direction = shortdirection; + x->effects.u.periodic.waveform = FF_SQUARE; + x->effects.u.periodic.period = 1000; + x->effects.u.periodic.magnitude = shortlevel; + x->effects.u.periodic.offset = 0; + x->effects.u.periodic.phase = 0; + x->effects.u.periodic.envelope.attack_length = 0x000; + x->effects.u.periodic.envelope.attack_level = 0; + x->effects.u.periodic.envelope.fade_length = 0x000; + x->effects.u.periodic.envelope.fade_level = 0; + x->effects.trigger.button = 0; + x->effects.trigger.interval = 0; + x->effects.replay.length = shortduration; + x->effects.replay.delay = 0; + x->device = device_number; + + ff_load(x); + + return (void*)x; +} + + + +/******************************************************************************************************** + +ff-spring and ff-friction methods + +*********************************************************************************************************/ + + +void ffCondition_setLevel(t_ff *x, t_floatarg level, int axis) +{ + unsigned short shortlevel; + + + if (x->ff_fd < 0) return; + + level = (level > 1 ? 1:level); + level = (level < 0 ? 0:level); + shortlevel = (unsigned short) (level * 65534 ); /*map level 0 to 1 to unsigned short range */ + + switch (axis) { + case 0: x->effects.u.condition[0].right_saturation = shortlevel; + break; + case 1: x->effects.u.condition[0].left_saturation = shortlevel; + break; + case 2: x->effects.u.condition[1].right_saturation = shortlevel; + break; + case 3: x->effects.u.condition[1].left_saturation = shortlevel; + break; + } + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + + +} + + + +void ffCondition_setCoeff(t_ff *x, t_floatarg coeff, int axis) +{ + short shortcoeff; + if (x->ff_fd < 0) return; + + coeff = (coeff > 1 ? 1:coeff); + coeff = (coeff < -1 ? -1:coeff); + shortcoeff = (short) (coeff * 32767 ); /*map level -1 to 1 to unsigned short range */ + switch (axis) { + case 0: x->effects.u.condition[0].right_coeff = shortcoeff; + break; + + case 1: x->effects.u.condition[0].left_coeff = shortcoeff; + break; + + case 2: x->effects.u.condition[1].right_coeff = shortcoeff; + break; + + + case 3: x->effects.u.condition[1].left_coeff = shortcoeff; + break; + } + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + +} + + +void ffCondition_deadband(t_ff *x, t_floatarg deadband, int axis) +{ + if (x->ff_fd < 0) return; + x->effects.u.condition[axis].deadband = (unsigned short)deadband; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + +} + +void ffCondition_center(t_ff *x, t_floatarg center, int axis) +{ + if (x->ff_fd < 0) return; + x->effects.u.condition[axis].center = (short)center; + + if (x->effects.id == -1) { + post("effect is not loaded, use a \"load\" message to upload to device"); + return; + } + + if (ioctl(x->ff_fd, EVIOCSFF, &x->effects) == -1) { + perror("Upload effects error"); + } + + +} + +void ffCondition_rightLevel(t_ff *x, t_floatarg rightLevel) +{ + + ffCondition_setLevel(x,rightLevel,0); + +} + +void ffCondition_leftLevel(t_ff *x, t_floatarg leftLevel) +{ + ffCondition_setLevel(x,leftLevel,1); + +} +void ffCondition_upLevel(t_ff *x, t_floatarg upLevel) +{ + ffCondition_setLevel(x,upLevel,3); + +} + +void ffCondition_downLevel(t_ff *x, t_floatarg downLevel) +{ + ffCondition_setLevel(x,downLevel,2); + +} + +void ffCondition_rightCoeff(t_ff *x, t_floatarg rightCoeff) +{ + ffCondition_setCoeff(x,rightCoeff,0); +} + +void ffCondition_leftCoeff(t_ff *x, t_floatarg leftCoeff) +{ + ffCondition_setCoeff(x,leftCoeff,1); +} +void ffCondition_upCoeff(t_ff *x, t_floatarg upCoeff) +{ + ffCondition_setCoeff(x,upCoeff,3); +} + +void ffCondition_downCoeff(t_ff *x, t_floatarg downCoeff) +{ + ffCondition_setCoeff(x,downCoeff,2); +} + + +void ffCondition_deadbandx(t_ff *x, t_floatarg deadband) +{ + ffCondition_deadband(x,deadband,0); +} + +void ffCondition_deadbandy(t_ff *x, t_floatarg deadband) +{ + ffCondition_deadband(x,deadband,1); +} + + +void ffCondition_centerx(t_ff *x, t_floatarg center) +{ + ffCondition_center(x,center,0); +} + + +void ffCondition_centery(t_ff *x, t_floatarg center) +{ + ffCondition_center(x,center,1); +} + + + +void *ffFriction_new(t_floatarg device,t_floatarg duration, t_floatarg rightLevel, t_floatarg leftLevel, + t_floatarg upLevel, t_floatarg downLevel) +{ + unsigned short shortduration,shortrightLevel,shortleftLevel,shortupLevel,shortdownLevel; + unsigned long features[4]; + int device_number; + + t_ff *x = (t_ff *)pd_new(ffFriction_class); + + device = (device > 4 ? 4:device); + device_number= (int)(device < 0 ? 0:device); + + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("duration")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("right-level")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("left-level")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("up-level")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("down-level")); + + outlet_new(&x->x_obj, &s_float); + + if ((x->ff_fd=open((char *) ff_dev[device_number].name, O_RDWR | O_NONBLOCK)) < 0) { + error("ff-lib:couldn't open %s, no effect will happen",ff_dev[device_number].name); + return (void *) x; + } + + if ((ioctl(x->ff_fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)) == -1) { + error("Couldn't determine available ff-effects \n FF probably won't work"); + close(x->ff_fd); + return (void *) x; + } + + if (!test_bit(FF_FRICTION, features)) { + error("Friction effect doesn't seem to be supported\n" + "the external won't do anything"); + close(x->ff_fd); + x->ff_fd = -1; + return (void *) x; + } + + + shortduration = (unsigned short) duration; + + rightLevel = (rightLevel > 1 ? 1:rightLevel); + rightLevel = (rightLevel < 0 ? 0:rightLevel); + shortrightLevel = (unsigned short) (rightLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + + leftLevel = (leftLevel > 1 ? 1:leftLevel); + leftLevel = (leftLevel < 0 ? 0:leftLevel); + shortleftLevel = (unsigned short) (leftLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + + upLevel = (upLevel > 1 ? 1:upLevel); + upLevel = (upLevel < 0 ? 0:upLevel); + shortupLevel = (unsigned short) (upLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + downLevel = (downLevel > 1 ? 1:downLevel); + downLevel = (downLevel < 0 ? 0:downLevel); + shortdownLevel = (unsigned short) (downLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + + + x->effects.type = FF_FRICTION; + x->effects.id = -1; + x->effects.u.condition[0].right_saturation = shortrightLevel; + x->effects.u.condition[0].left_saturation = shortleftLevel; + x->effects.u.condition[0].right_coeff = 0x8000; + x->effects.u.condition[0].left_coeff = 0x8000; + x->effects.u.condition[0].deadband = 0; + x->effects.u.condition[0].center = 0; + x->effects.u.condition[1].right_saturation = shortdownLevel; + x->effects.u.condition[1].left_saturation = shortupLevel; + x->effects.u.condition[1].right_coeff = 0x8000; + x->effects.u.condition[1].left_coeff = 0x8000; + x->effects.u.condition[1].deadband = 0; + x->effects.u.condition[1].center = 0; + x->effects.trigger.button = 0; + x->effects.trigger.interval = 0; + x->effects.replay.length = shortduration; + x->effects.replay.delay = 0; + x->device = device_number; + + + ff_load(x); + + return (void*)x; +} + +void *ffSpring_new(t_floatarg device,t_floatarg duration, t_floatarg rightLevel, t_floatarg leftLevel, + t_floatarg upLevel, t_floatarg downLevel) +{ + unsigned short shortduration,shortrightLevel,shortleftLevel,shortupLevel,shortdownLevel; + unsigned long features[4]; + int device_number; + + t_ff *x = (t_ff *)pd_new(ffFriction_class); + + device = (device > 4 ? 4:device); + device_number= (int)(device < 0 ? 0:device); + + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("duration")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("right-level")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("left-level")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("up-level")); + inlet_new(&x->x_obj, + &x->x_obj.ob_pd, + gensym("float"), + gensym("down-level")); + + outlet_new(&x->x_obj, &s_float); + + if ((x->ff_fd=open((char *) ff_dev[device_number].name, O_RDWR | O_NONBLOCK)) < 0) { + error("ff-lib:couldn't open %s, no effect will happen",ff_dev[device_number].name); + return (void *) x; + } + + if ((ioctl(x->ff_fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features)) == -1) { + error("Couldn't determine available ff-effects \n FF probably won't work"); + close(x->ff_fd); + return (void *) x; + } + + if (!test_bit(FF_SPRING, features)) { + error("Spring effect doesn't seem to be supported\n" + "the external won't do anything"); + close(x->ff_fd); + x->ff_fd = -1; + return (void *) x; + } + + shortduration = (unsigned short) duration; + + leftLevel = (leftLevel > 1 ? 1:leftLevel); + leftLevel = (leftLevel < 0 ? 0:leftLevel); + shortleftLevel = (unsigned short) (leftLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + rightLevel = (rightLevel > 1 ? 1:rightLevel); + rightLevel = (rightLevel < 0 ? 0:rightLevel); + shortrightLevel = (unsigned short) (rightLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + upLevel = (upLevel > 1 ? 1:upLevel); + upLevel = (upLevel < 0 ? 0:upLevel); + shortupLevel = (unsigned short) (upLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + downLevel = (downLevel > 1 ? 1:downLevel); + downLevel = (downLevel < 0 ? 0:downLevel); + shortdownLevel = (unsigned short) (downLevel * 65534 ); /*map level 0 to 1 to unsigned short range */ + + + x->effects.type = FF_SPRING; + x->effects.id = -1; + x->effects.u.condition[0].right_saturation = shortrightLevel; + x->effects.u.condition[0].left_saturation = shortleftLevel; + x->effects.u.condition[0].right_coeff = 0x8000; + x->effects.u.condition[0].left_coeff = 0x8000; + x->effects.u.condition[0].deadband = 0; + x->effects.u.condition[0].center = 0; + x->effects.u.condition[1].right_saturation = shortdownLevel; + x->effects.u.condition[1].left_saturation = shortupLevel; + x->effects.u.condition[1].right_coeff = 0x8000; + x->effects.u.condition[1].left_coeff = 0x8000; + x->effects.u.condition[1].deadband = 0; + x->effects.u.condition[1].center = 0; + x->effects.trigger.button = 0; + x->effects.trigger.interval = 0; + x->effects.replay.length = shortduration; + x->effects.replay.delay = 0; + x->device = device_number; + + ff_load(x); + + return (void*)x; +} + +/******************************************************************************************************** + +ff-gain methods + +*********************************************************************************************************/ + + +void ffGain_set(t_ff *x, t_floatarg gain) +{ + gain = (gain > 1 ? 1:gain); + gain = (gain < 0 ? 0:gain); + + x->do_that.type = EV_FF; + x->do_that.code = FF_GAIN; + x->do_that.value = (unsigned int)(65536.0 * gain); + if (x->ff_fd > 0) + if ((write(x->ff_fd, (const void*) &x->do_that, sizeof(x->do_that))) == -1) + error("ff-lib: couldn't set gain"); + +} + + + + + +void *ffGain_new(t_floatarg device,t_floatarg gain) +{ + int device_number; + unsigned short shortgain; + t_ff *x = (t_ff *)pd_new(ffGain_class); + + device = (device > 4 ? 4:device); + device_number= (int)(device < 0 ? 0:device); + + gain = (gain > 1 ? 1:gain); + gain = (gain < 0 ? 0:gain); + shortgain = (unsigned short) (gain * 65536); + if ((x->ff_fd=open((char *) ff_dev[device_number].name, O_RDWR | O_NONBLOCK)) < 0) { + error("ff-lib:couldn't open %s, no effect will happen",ff_dev[device_number].name); + return (void *) x; + } + x->do_that.type = EV_FF; + x->do_that.code = FF_GAIN; + x->do_that.value = shortgain; + + if ((write(x->ff_fd, (const void*) &x->do_that, sizeof(x->do_that))) == -1) + error("ff-lib: couldn't set gain"); + return (void*)x; +} + + +/******************************************************************************************************** + +ff-autocenter methods + +*********************************************************************************************************/ + +void ffAutocenter_set(t_ff *x, t_floatarg autocenter) +{ + + autocenter = (autocenter > 1 ? 1:autocenter); + autocenter = (autocenter < -1 ? -1:autocenter); + + x->do_that.type = EV_FF; + x->do_that.code = FF_AUTOCENTER; + x->do_that.value = (short)(32767.0 * autocenter); + if (x->ff_fd > 0) + if ((write(x->ff_fd, (const void*) &x->do_that, sizeof(x->do_that))) == -1) + error("ff-lib:couldn't set autocenter"); + +} + + +void *ffAutocenter_new(t_floatarg device,t_floatarg autocenter) +{ + int device_number; + t_ff *x = (t_ff *)pd_new(ffAutocenter_class); + device = (device > 4 ? 4:device); + device_number= (int)(device < 0 ? 0:device); + + autocenter = (autocenter > 1 ? 1:autocenter); + autocenter = (autocenter < 0 ? 0:autocenter); + + if ((x->ff_fd=open((char *) ff_dev[device_number].name, O_RDWR | O_NONBLOCK)) < 0) { + error("ff-lib:couldn't open %s, no effect will happen", ff_dev[device_number].name); + return (void *) x; + } + x->do_that.type = EV_FF; + x->do_that.code = FF_AUTOCENTER; + x->do_that.value = (short)(32767.0 * autocenter ); + + if ((write(x->ff_fd, (const void*) &x->do_that, sizeof(x->do_that))) == -1) + error("ff-lib:couldn't set autocenter"); + return (void *) x; + +} + + + + + + + + +/****************************************************************************************** +initialisation functions +*******************************************************************************************/ + +void add_general_ff_methods(t_class* ff_class) +{ + class_addbang(ff_class,ff_bang); + class_addmethod(ff_class, (t_method)ff_stop,gensym("stop"),0); + class_addmethod(ff_class, (t_method)ff_duration,gensym("duration"),A_DEFFLOAT,0); + class_addmethod(ff_class, (t_method)ff_interval,gensym("interval"),A_DEFFLOAT,0); + class_addmethod(ff_class, (t_method)ff_delay,gensym("delay"),A_DEFFLOAT,0); + class_addmethod(ff_class, (t_method)ff_load,gensym("load"),0); + class_addmethod(ff_class, (t_method)ff_unload,gensym("unload"),0); +} + +void init_ffConstant(void) +{ + + ffConstant_class = class_new(gensym("ff-constant"), + (t_newmethod)ffConstant_new, + (t_method)ff_free, + sizeof(t_ff), + CLASS_DEFAULT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + + add_general_ff_methods(ffConstant_class); + class_addmethod(ffConstant_class, + (t_method)ff_direction, + gensym("direction"), + A_DEFFLOAT, + 0); + class_addmethod(ffConstant_class, + (t_method)ffConstant_level, + gensym("level"), + A_DEFFLOAT, + 0); + class_addmethod(ffConstant_class, + (t_method)ffConstant_envelope, + gensym("envelope"), + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + +} + +void init_ffPeriodic(void) +{ + ffPeriodic_class = class_new(gensym("ff-periodic"), + (t_newmethod)ffPeriodic_new, + (t_method)ff_free, + sizeof(t_ff), + CLASS_DEFAULT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + add_general_ff_methods(ffPeriodic_class); + class_addmethod(ffPeriodic_class, + (t_method)ff_direction, + gensym("direction"), + A_DEFFLOAT, + 0); + class_addmethod(ffPeriodic_class, + (t_method)ffPeriodic_level, + gensym("level"), + A_DEFFLOAT, + 0); + class_addmethod(ffPeriodic_class, + (t_method)ffPeriodic_envelope, + gensym("envelope"), + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + class_addmethod(ffPeriodic_class, + (t_method)ffPeriodic_waveform, + gensym("waveform"), + A_DEFSYMBOL, + 0); + class_addmethod(ffPeriodic_class, + (t_method)ffPeriodic_period, + gensym("period"), + A_DEFFLOAT, + 0); + class_addmethod(ffPeriodic_class, + (t_method)ffPeriodic_offset, + gensym("offset"), + A_DEFFLOAT, + 0); + class_addmethod(ffPeriodic_class, + (t_method)ffPeriodic_phase, + gensym("phase"), + A_DEFFLOAT, + 0); + + + + +} + +void init_ffSpring(void) +{ + ffSpring_class = class_new(gensym("ff-spring"), + (t_newmethod)ffSpring_new, + (t_method)ff_free, + sizeof(t_ff), + CLASS_DEFAULT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + add_general_ff_methods(ffSpring_class); + + class_addmethod(ffSpring_class, + (t_method)ffCondition_rightLevel, + gensym("right-level"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_leftLevel, + gensym("left-level"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_upLevel, + gensym("up-level"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_downLevel, + gensym("down-level"), + A_DEFFLOAT, + 0); + + + class_addmethod(ffSpring_class, + (t_method)ffCondition_rightCoeff, + gensym("right-coeff"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_leftCoeff, + gensym("left-coeff"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_upCoeff, + gensym("up-coeff"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_downCoeff, + gensym("down-coeff"), + A_DEFFLOAT, + 0); + + class_addmethod(ffSpring_class, + (t_method)ffCondition_deadbandx, + gensym("deadband-x"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_deadbandy, + gensym("deadband-y"), + A_DEFFLOAT, + 0); + + class_addmethod(ffSpring_class, + (t_method)ffCondition_centerx, + gensym("center-x"), + A_DEFFLOAT, + 0); + class_addmethod(ffSpring_class, + (t_method)ffCondition_centery, + gensym("center-y"), + A_DEFFLOAT, + 0); + + +} + +void init_ffFriction(void) +{ + ffFriction_class = class_new(gensym("ff-friction"), + (t_newmethod)ffFriction_new, + (t_method)ff_free, + sizeof(t_ff), + CLASS_DEFAULT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + add_general_ff_methods(ffFriction_class); + + class_addmethod(ffFriction_class, + (t_method)ffCondition_rightLevel, + gensym("right-level"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_leftLevel, + gensym("left-level"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_upLevel, + gensym("up-level"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_downLevel, + gensym("down-level"), + A_DEFFLOAT, + 0); + + class_addmethod(ffFriction_class, + (t_method)ffCondition_rightCoeff, + gensym("right-coeff"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_leftCoeff, + gensym("left-coeff"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_upCoeff, + gensym("up-coeff"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_downCoeff, + gensym("down-coeff"), + A_DEFFLOAT, + 0); + + class_addmethod(ffFriction_class, + (t_method)ffCondition_deadbandx, + gensym("deadband-x"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_centerx, + gensym("center-x"), + A_DEFFLOAT, + 0); + + + class_addmethod(ffFriction_class, + (t_method)ffCondition_deadbandy, + gensym("deadband-y"), + A_DEFFLOAT, + 0); + class_addmethod(ffFriction_class, + (t_method)ffCondition_centery, + gensym("center-y"), + A_DEFFLOAT, + 0); + +} + +void init_ffGain(void) + +{ + ffGain_class = class_new(gensym("ff-gain"), + (t_newmethod)ffGain_new, + 0, + sizeof(t_ff), + CLASS_DEFAULT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + + class_addfloat(ffGain_class,(t_method)ffGain_set); + +} + +void init_ffAutocenter(void) +{ + ffAutocenter_class = class_new(gensym("ff-autocenter"), + (t_newmethod)ffAutocenter_new, + 0, + sizeof(t_ff), + CLASS_DEFAULT, + A_DEFFLOAT, + A_DEFFLOAT, + 0); + + class_addfloat(ffAutocenter_class,(t_method)ffAutocenter_set); + +} + + +void ff_setup(void) +{ + /* open event device and determine available effects and memory */ + /* the externals themselves also check, this is just to give some info to the user on startup */ + + + char device_file_name[4][18]; + unsigned long features[4]; + int n_effects; /* Number of effects the device can play at the same time */ + int j,ffdevice_count,fftest,fd; + + post("//////////////////////////////////////////\n" + "/////Force feedback external library///// \n" + "////Gerard van Dongen, gml@xs4all.nl//// \n" + "///testing for available ff devices////.\n" + "//////////////////////////////////////"); + + + ffdevice_count = 0; + for (j=0;j<4;j++){ + fftest = 0; + sprintf(device_file_name[j], "/dev/input/event%i",j); + + /* Open device */ + fd = open(device_file_name[j], O_RDWR | O_NONBLOCK); + if (fd == -1) { + continue; + } + post("Device %s opened\n", device_file_name[j]); + + /* Query device */ + if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features) == -1) { + error("Couldn't determine available ff-effects \n FF probablz won't work"); + close(fd); + continue; + } + post("the following externals will work on %s",device_file_name[j]); + + if (test_bit(FF_CONSTANT, features)) { + post("ff-constant "); + fftest++; + } + if (test_bit(FF_PERIODIC, features)) { + post("ff-periodic "); + fftest++; + } + if (test_bit(FF_SPRING, features)) { + post("ff-spring "); + fftest++; + } + if (test_bit(FF_FRICTION, features)) { + post("ff-friction "); + fftest++; + } + if (test_bit(FF_RUMBLE, features)) { + post("The rumble effect is supported by the device,\n" + "but there is no external to control this in pd (yet) "); + fftest++; + } + if (test_bit(FF_RAMP, features)) { + post("The ramp effect is supported by the device,\n" + "but there is no external to control this in pd (yet) "); + fftest++; + } + if (test_bit(FF_DAMPER, features)){ + post("The damper effect is supported by the device,\n" + "but there is no external to control this in pd (yet) "); + fftest++; + } + if (test_bit(FF_INERTIA, features)){ + post("The inertia effect is supported by the device,\n" + "but there is no external to control this in pd (yet) "); + fftest++; + } + + + if (ioctl(fd, EVIOCGEFFECTS, &n_effects) == -1) { + error("Ioctl number of effects"); + } + post("Number of simultaneous effects: %i",n_effects); + + close(fd); + if (fftest != 0 && n_effects !=0) { + ffdevice_count++; + ff_dev[j].max_fx = n_effects; + ff_dev[j].loaded_fx = 0; + strncpy(ff_dev[j].name,device_file_name[j],64); + } + + } + + if (ffdevice_count >0) + post("%i ff-device(s) found",ffdevice_count); + else + post("NO ff capable devices found"); + + + init_ffConstant(); + init_ffPeriodic(); + init_ffSpring(); + init_ffFriction(); + init_ffGain(); + init_ffAutocenter(); +} + + + + diff --git a/ff/input.h b/ff/input.h new file mode 100644 index 0000000..970e163 --- /dev/null +++ b/ff/input.h @@ -0,0 +1,831 @@ +#ifndef _INPUT_H +#define _INPUT_H + +/* + * $Id: input.h,v 1.1.1.1 2003-10-18 13:37:21 vdongen Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#ifdef __KERNEL__ +#include +#else +#include +#include +#include +#endif + +/* + * The event structure itself + */ + +struct input_event { + struct timeval time; + unsigned short type; + unsigned short code; + unsigned int value; +}; + +/* + * Protocol version. + */ + +#define EV_VERSION 0x010000 + +/* + * IOCTLs (0x00 - 0x7f) + */ + +#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ +#define EVIOCGID _IOR('E', 0x02, short[4]) /* get device ID */ +#define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */ +#define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */ +#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ +#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ + +#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ +#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, int[5]) /* get abs value/limits */ + +#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ +#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ +#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ + +/* + * Event types + */ + +#define EV_RST 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f + +/* + * Keys and buttons + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 +#define KEY_103RD 84 +#define KEY_F13 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_F14 89 +#define KEY_F15 90 +#define KEY_F16 91 +#define KEY_F17 92 +#define KEY_F18 93 +#define KEY_F19 94 +#define KEY_F20 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_F21 120 +#define KEY_F22 121 +#define KEY_F23 122 +#define KEY_F24 123 +#define KEY_KPCOMMA 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 +#define KEY_COMPUTER 157 +#define KEY_BACK 158 +#define KEY_FORWARD 159 +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 +#define KEY_ISO 170 +#define KEY_CONFIG 171 +#define KEY_HOMEPAGE 172 +#define KEY_REFRESH 173 +#define KEY_EXIT 174 +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 + +#define KEY_INTL1 181 +#define KEY_INTL2 182 +#define KEY_INTL3 183 +#define KEY_INTL4 184 +#define KEY_INTL5 185 +#define KEY_INTL6 186 +#define KEY_INTL7 187 +#define KEY_INTL8 188 +#define KEY_INTL9 189 +#define KEY_LANG1 190 +#define KEY_LANG2 191 +#define KEY_LANG3 192 +#define KEY_LANG4 193 +#define KEY_LANG5 194 +#define KEY_LANG6 195 +#define KEY_LANG7 196 +#define KEY_LANG8 197 +#define KEY_LANG9 198 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 + +#define KEY_UNKNOWN 240 + +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_MAX 0x1ff + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f + +/* + * Misc events + */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_MAX 0x07 + +/* + * LEDs + */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAX 0x0f + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_MAX 0x07 + +/* + * IDs. + */ + +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 + +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 + +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 + +/* + * Values describing the status of an effect + */ +#define FF_STATUS_STOPPED 0x00 +#define FF_STATUS_PLAYING 0x01 +#define FF_STATUS_MAX 0x01 + +/* + * Structures used in ioctls to upload effects to a device + * The first structures are not passed directly by using ioctls. + * They are sub-structures of the actually sent structure (called ff_effect) + */ + +struct ff_replay { + __u16 length; /* Duration of an effect in ms. + All other times are also expressed in ms. + 0 means "play for ever" */ + __u16 delay; /* Time to wait before to start playing an effect */ +}; + +struct ff_trigger { + __u16 button; /* Number of button triggering an effect */ + __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ +}; + +struct ff_envelope { + __u16 attack_length; /* Duration of attack (ms) */ + __u16 attack_level; /* Level at beginning of attack */ + __u16 fade_length; /* Duration of fade (ms) */ + __u16 fade_level; /* Level at end of fade */ +}; + +/* FF_CONSTANT */ +struct ff_constant_effect { + __s16 level; /* Strength of effect. Negative values are OK */ + struct ff_envelope envelope; +}; + +/* FF_RAMP */ +struct ff_ramp_effect { + __s16 start_level; + __s16 end_level; + struct ff_envelope envelope; +}; + +/* FF_SPRING of FF_FRICTION */ +struct ff_condition_effect { + __u16 right_saturation; /* Max level when joystick is on the right */ + __u16 left_saturation; /* Max level when joystick in on the left */ + + __s16 right_coeff; /* Indicates how fast the force grows when the + joystick moves to the right */ + __s16 left_coeff; /* Same for left side */ + + __u16 deadband; /* Size of area where no force is produced */ + __s16 center; /* Position of dead zone */ + +}; + +/* FF_PERIODIC */ +struct ff_periodic_effect { + __u16 waveform; /* Kind of wave (sine, square...) */ + __u16 period; /* in ms */ + __s16 magnitude; /* Peak value */ + __s16 offset; /* Mean value of wave (roughly) */ + __u16 phase; /* 'Horizontal' shift */ + + struct ff_envelope envelope; + +/* Only used if waveform == FF_CUSTOM */ + __u32 custom_len; /* Number of samples */ + __s16 *custom_data; /* Buffer of samples */ +/* Note: the data pointed by custom_data is copied by the driver. You can + * therefore dispose of the memory after the upload/update */ +}; + +/* FF_RUMBLE */ +/* Some rumble pads have two motors of different weight. + strong_magnitude represents the magnitude of the vibration generated + by the heavy motor. +*/ +struct ff_rumble_effect { + __u16 strong_magnitude; /* Magnitude of the heavy motor */ + __u16 weak_magnitude; /* Magnitude of the light one */ +}; + +/* + * Structure sent through ioctl from the application to the driver + */ +struct ff_effect { + __u16 type; +/* Following field denotes the unique id assigned to an effect. + * If user sets if to -1, a new effect is created, and its id is returned in the same field + * Else, the user sets it to the effect id it wants to update. + */ + __s16 id; + + __u16 direction; /* Direction. 0 deg -> 0x0000 (down) + 90 deg -> 0x4000 (left) + 180 deg -> 0x8000 (up) + 270 deg -> 0xC000 (right) + */ + + struct ff_trigger trigger; + struct ff_replay replay; + + union { + struct ff_constant_effect constant; + struct ff_ramp_effect ramp; + struct ff_periodic_effect periodic; + struct ff_condition_effect condition[2]; /* One for each axis */ + struct ff_rumble_effect rumble; + } u; +}; + +/* + * Force feedback effect types + */ + +#define FF_RUMBLE 0x50 +#define FF_PERIODIC 0x51 +#define FF_CONSTANT 0x52 +#define FF_SPRING 0x53 +#define FF_FRICTION 0x54 +#define FF_DAMPER 0x55 +#define FF_INERTIA 0x56 +#define FF_RAMP 0x57 + +/* + * Force feedback periodic effect types + */ + +#define FF_SQUARE 0x58 +#define FF_TRIANGLE 0x59 +#define FF_SINE 0x5a +#define FF_SAW_UP 0x5b +#define FF_SAW_DOWN 0x5c +#define FF_CUSTOM 0x5d + +/* + * Set ff device properties + */ + +#define FF_GAIN 0x60 +#define FF_AUTOCENTER 0x61 + +#define FF_MAX 0x7f + +#ifdef __KERNEL__ + +/* + * In-kernel definitions. + */ + +#include +#include + +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) +#define LONG(x) ((x)/BITS_PER_LONG) + +struct input_dev { + + void *private; + + char *name; + char *phys; + char *uniq; + unsigned short idbus; + unsigned short idvendor; + unsigned short idproduct; + unsigned short idversion; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + int ff_effects_max; + + unsigned int keycodemax; + unsigned int keycodesize; + void *keycode; + + unsigned int repeat_key; + struct timer_list timer; + + struct pm_dev *pm_dev; + int state; + + int abs[ABS_MAX + 1]; + int rep[REP_MAX + 1]; + + unsigned long key[NBITS(KEY_MAX)]; + unsigned long led[NBITS(LED_MAX)]; + unsigned long snd[NBITS(SND_MAX)]; + + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; + + int (*open)(struct input_dev *dev); + void (*close)(struct input_dev *dev); + int (*accept)(struct input_dev *dev, struct file *file); + int (*flush)(struct input_dev *dev, struct file *file); + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); + int (*erase_effect)(struct input_dev *dev, int effect_id); + + struct input_handle *handle; + struct input_dev *next; +}; + +/* + * Structure for hotplug & device<->driver matching. + */ + +#define INPUT_DEVICE_ID_MATCH_BUS 1 +#define INPUT_DEVICE_ID_MATCH_VENDOR 2 +#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 +#define INPUT_DEVICE_ID_MATCH_VERSION 8 + +#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010 +#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020 +#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040 +#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080 +#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100 +#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200 +#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400 +#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800 + +#define INPUT_DEVICE_ID_MATCH_DEVICE\ + (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) +#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\ + (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) + +struct input_device_id { + + unsigned long flags; + + unsigned short idbus; + unsigned short idvendor; + unsigned short idproduct; + unsigned short idversion; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + + unsigned long driver_info; +}; + +struct input_handler { + + void *private; + + void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); + void (*disconnect)(struct input_handle *handle); + + struct file_operations *fops; + int minor; + char *name; + + struct input_device_id *id_table; + + struct input_handle *handle; + struct input_handler *next; +}; + +struct input_handle { + + void *private; + + int open; + char *name; + + struct input_dev *dev; + struct input_handler *handler; + + struct input_handle *dnext; + struct input_handle *hnext; +}; + +void input_register_device(struct input_dev *); +void input_unregister_device(struct input_dev *); + +void input_register_handler(struct input_handler *); +void input_unregister_handler(struct input_handler *); + +int input_open_device(struct input_handle *); +void input_close_device(struct input_handle *); + +int input_accept_process(struct input_handle *handle, struct file *file); +int input_flush_device(struct input_handle* handle, struct file* file); + +devfs_handle_t input_register_minor(char *name, int minor, int minor_base); +void input_unregister_minor(devfs_handle_t handle); + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) +#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) +#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) +#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c) +#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c) + +#endif +#endif diff --git a/ff/makefile b/ff/makefile new file mode 100644 index 0000000..99554e3 --- /dev/null +++ b/ff/makefile @@ -0,0 +1,7 @@ +ff: ff.c + gcc $(CFLAGS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o ff.o -c ff.c + ld -export_dynamic -shared -o ff.pd_linux ff.o -lc -lm + strip --strip-unneeded ff.pd_linux + rm ff.o + + diff --git a/ff/multi.pd b/ff/multi.pd new file mode 100644 index 0000000..47f9204 --- /dev/null +++ b/ff/multi.pd @@ -0,0 +1,23 @@ +#N canvas 0 0 450 300 10; +#X obj 178 47 ff-constant 0; +#X obj 185 138 ff-constant 0; +#X obj 172 69 ff-constant 0; +#X obj 176 94 ff-constant 0; +#X obj 174 114 ff-constant 0; +#X obj 192 166 ff-constant 0; +#X obj 194 194 ff-constant 0; +#X obj 204 219 ff-constant 0; +#X obj 209 242 ff-constant 0; +#X obj 231 265 ff-constant 0; +#X obj 350 45 ff-constant 0; +#X msg 315 16 load; +#X msg 212 15 unload; +#X msg 128 17 bang; +#X floatatom 347 99 5 0 0 0 - - -; +#X obj 25 182 ff-constant 0; +#X floatatom 31 223 5 0 0 0 - - -; +#X connect 10 0 14 0; +#X connect 11 0 10 0; +#X connect 12 0 3 0; +#X connect 13 0 0 0; +#X connect 15 0 16 0; -- cgit v1.2.1 From efd2b4d0f80af449b90b7b5ccfccb575f723d55d Mon Sep 17 00:00:00 2001 From: Gerard van Dongen Date: Mon, 27 Oct 2003 15:37:49 +0000 Subject: updated makefiles to include beatpipe renamed help patches for ff externals to foo-help.pd svn path=/trunk/externals/ff/; revision=1139 --- ff/ff-autocenter.pd | 9 -------- ff/ff-constant.pd | 39 -------------------------------- ff/ff-gain.pd | 8 ------- ff/ff-periodic.pd | 44 ------------------------------------ ff/ff-spring.pd | 65 ----------------------------------------------------- ff/multi.pd | 23 ------------------- 6 files changed, 188 deletions(-) delete mode 100644 ff/ff-autocenter.pd delete mode 100644 ff/ff-constant.pd delete mode 100644 ff/ff-gain.pd delete mode 100644 ff/ff-periodic.pd delete mode 100644 ff/ff-spring.pd delete mode 100644 ff/multi.pd diff --git a/ff/ff-autocenter.pd b/ff/ff-autocenter.pd deleted file mode 100644 index 323afd8..0000000 --- a/ff/ff-autocenter.pd +++ /dev/null @@ -1,9 +0,0 @@ -#N canvas 393 404 450 300 10; -#X text 30 34 sets the amount of "autocentering" of the force-feedback -joystick. Range is [0 \, 1]. 0 is no auto-centering; -#X msg 48 141 0.5; -#X obj 48 191 ff-autocenter 0 0; -#X text 29 69 creation arguments are the device number (starting at -0) and autocenter amount. This affects all effects for that device -; -#X connect 1 0 2 0; diff --git a/ff/ff-constant.pd b/ff/ff-constant.pd deleted file mode 100644 index 48a8fb7..0000000 --- a/ff/ff-constant.pd +++ /dev/null @@ -1,39 +0,0 @@ -#N canvas 161 237 742 413 10; -#X msg 68 150 bang; -#X msg 44 213 stop; -#X floatatom 301 269 5 0 0 0 - - -; -#X floatatom 187 214 5 0 0 0 - - -; -#X text 185 196 direction in degrees; -#X floatatom 244 249 5 0 0 0 - - -; -#X text 340 264 level \, range = [-1 \, 1]; -#X text 7 130 start the effect; -#X text 12 146 with a; -#X msg 131 77 delay 250; -#X msg 131 48 interval 500; -#X text 229 79 delay before starting; -#X text 229 50 minimum time between triggers; -#X obj 131 290 ff-constant 0 45 1000 0.5; -#X text 107 314 arguments are inputdevice-number \, direction \, duration -and level; -#X msg 131 151 load; -#X msg 131 175 unload; -#X text 191 150 a load message \, uploads an effect to the stick; -#X text 190 175 an unload message \, removes it; -#X text 303 110 startlevel attack-duration (ms) endlevel decay-duration -; -#X msg 131 112 envelope 0 500 0.5 100; -#X text 300 125 levels are in the range [0 \, 1].; -#X text 109 352 the outlet gives the effect number on the device or --1 if it is not loaded.; -#X text 241 221 duration in ms \, 0 is infinite \, this includes the -attack/decay times; -#X connect 0 0 13 0; -#X connect 1 0 13 0; -#X connect 2 0 13 3; -#X connect 3 0 13 1; -#X connect 5 0 13 2; -#X connect 9 0 13 0; -#X connect 10 0 13 0; -#X connect 15 0 13 0; -#X connect 16 0 13 0; -#X connect 20 0 13 0; diff --git a/ff/ff-gain.pd b/ff/ff-gain.pd deleted file mode 100644 index 94b1008..0000000 --- a/ff/ff-gain.pd +++ /dev/null @@ -1,8 +0,0 @@ -#N canvas 0 0 450 300 10; -#X text 26 62 sets the overall gain [0 \, 1] of the force-feedback -joystick on the device.; -#X msg 74 182 0.3; -#X obj 74 222 ff-gain 0 0.5; -#X text 24 105 creation arguments are the device-number (starting at -0) and gain. This effects all effects for that device; -#X connect 1 0 2 0; diff --git a/ff/ff-periodic.pd b/ff/ff-periodic.pd deleted file mode 100644 index f280692..0000000 --- a/ff/ff-periodic.pd +++ /dev/null @@ -1,44 +0,0 @@ -#N canvas 155 183 711 418 10; -#X msg 27 211 bang; -#X msg 3 274 stop; -#X floatatom 340 294 5 0 0 0 - - -; -#X msg 87 12 waveform sine; -#X msg 87 35 period 400; -#X msg 87 86 phase 90; -#X msg 87 60 offset 0.25; -#X text 192 13 square|sine|triangle|saw_up|saw_down; -#X text 192 35 period time in ms (defaults 1000 ms); -#X text 194 59 waveform offset from center [-1 \, 1] (defaults 0=centered) -; -#X floatatom 169 234 5 0 0 0 - - -; -#X text 164 210 direction in degrees; -#X floatatom 257 263 5 0 0 0 - - -; -#X text 338 274 level \, range = [-1 \, 1]; -#X text 255 89 waveform phase in degrees; -#X text -34 191 start the effect; -#X text -29 207 with a; -#X msg 87 139 delay 250; -#X msg 87 113 interval 500; -#X text 255 143 delay before starting; -#X text 257 114 minimum time between triggers; -#X obj 87 329 ff-periodic 0 0 0 0.5; -#X text 90 354 arguments are device-number \, duration and level; -#X msg 87 168 envelope 0 1000 0 100; -#X text 259 160 startlevel attack-duration endlevel decay-duration -levels or in the range [0 \, 1]; -#X text 254 226 duration in ms \, 0 is infinite \, this includes the -attack/decay times; -#X text 90 370 the outlet gives the effect number on the device or --1 if it is not loaded.; -#X connect 0 0 21 0; -#X connect 1 0 21 0; -#X connect 2 0 21 3; -#X connect 3 0 21 0; -#X connect 4 0 21 0; -#X connect 5 0 21 0; -#X connect 6 0 21 0; -#X connect 10 0 21 1; -#X connect 12 0 21 2; -#X connect 17 0 21 0; -#X connect 18 0 21 0; -#X connect 23 0 21 0; diff --git a/ff/ff-spring.pd b/ff/ff-spring.pd deleted file mode 100644 index 980ff2c..0000000 --- a/ff/ff-spring.pd +++ /dev/null @@ -1,65 +0,0 @@ -#N canvas 173 83 685 588 10; -#X msg 46 262 bang; -#X msg 102 261 stop; -#X text 39 242 with a; -#X msg 141 129 delay 250; -#X msg 141 104 interval 500; -#X text 275 130 delay before starting; -#X text 239 104 minimum time between triggers; -#X text 292 192 coefficients that determine how fast; -#X text 292 204 the effect increases in that direction; -#X text 292 215 range = [-1 \, 1]; -#X text 261 279 width of the dead-zone \, where there is no effect -; -#X text 261 303 range is (like the joystick output) [-32768 \, 32767] -; -#X text 262 290 one for each axis; -#X text 262 332 position of the dead-zone in the joystick range; -#X text 262 344 one for each axis; -#X text 262 356 range is also [-32768 \, 32767]; -#X floatatom 204 411 5 0 0 0 - - -; -#X floatatom 331 458 5 0 0 0 - - -; -#X floatatom 267 458 5 0 0 0 - - -; -#X text 200 388 duration in ms \, 0 is infinite; -#X floatatom 394 458 5 0 0 0 - - -; -#X floatatom 458 461 5 0 0 0 - - -; -#X text 267 422 levels \, range = [0 \, 1]; -#X text 266 439 right; -#X text 332 438 left; -#X text 392 438 up; -#X text 458 439 down; -#X text 34 229 start; -#X text 4 79 ff-friction has the same methods; -#X text 5 33 ff-spring is a "conditional effect".; -#X obj 141 484 ff-spring 0 2000 0.5 0.5 0 0.1; -#X text 141 507 creation arguments are device-number \, duration right- -\, left- \, up- and down-level; -#X msg 141 281 deadband-x 1200; -#X msg 141 306 deadband-y 300; -#X msg 141 335 center-x 0; -#X msg 141 358 center-y 20000; -#X msg 141 195 left-coeff 1; -#X msg 141 173 right-coeff 1; -#X msg 141 219 up-coeff -0.7; -#X msg 141 242 down-coeff -1; -#X text 6 49 these effects set up 2 axes (x and y) and you specify -the parameters for each direction.; -#X text 139 540 the outlet gives the effect number on the device or --1 if it is not loaded.; -#X connect 0 0 30 0; -#X connect 1 0 30 0; -#X connect 3 0 30 0; -#X connect 4 0 30 0; -#X connect 16 0 30 1; -#X connect 17 0 30 3; -#X connect 18 0 30 2; -#X connect 20 0 30 4; -#X connect 21 0 30 5; -#X connect 32 0 30 0; -#X connect 33 0 30 0; -#X connect 34 0 30 0; -#X connect 35 0 30 0; -#X connect 36 0 30 0; -#X connect 37 0 30 0; -#X connect 38 0 30 0; -#X connect 39 0 30 0; diff --git a/ff/multi.pd b/ff/multi.pd deleted file mode 100644 index 47f9204..0000000 --- a/ff/multi.pd +++ /dev/null @@ -1,23 +0,0 @@ -#N canvas 0 0 450 300 10; -#X obj 178 47 ff-constant 0; -#X obj 185 138 ff-constant 0; -#X obj 172 69 ff-constant 0; -#X obj 176 94 ff-constant 0; -#X obj 174 114 ff-constant 0; -#X obj 192 166 ff-constant 0; -#X obj 194 194 ff-constant 0; -#X obj 204 219 ff-constant 0; -#X obj 209 242 ff-constant 0; -#X obj 231 265 ff-constant 0; -#X obj 350 45 ff-constant 0; -#X msg 315 16 load; -#X msg 212 15 unload; -#X msg 128 17 bang; -#X floatatom 347 99 5 0 0 0 - - -; -#X obj 25 182 ff-constant 0; -#X floatatom 31 223 5 0 0 0 - - -; -#X connect 10 0 14 0; -#X connect 11 0 10 0; -#X connect 12 0 3 0; -#X connect 13 0 0 0; -#X connect 15 0 16 0; -- cgit v1.2.1 From e16a35b811019cf0c54c26078243fc8cc5a87916 Mon Sep 17 00:00:00 2001 From: Gerard van Dongen Date: Mon, 27 Oct 2003 15:40:42 +0000 Subject: added renamed ff help patches svn path=/trunk/externals/ff/; revision=1140 --- ff/ff-autocenter-help.pd | 9 +++++++ ff/ff-constant-help.pd | 39 +++++++++++++++++++++++++++++ ff/ff-gain-help.pd | 8 ++++++ ff/ff-periodic-help.pd | 44 ++++++++++++++++++++++++++++++++ ff/ff-spring-help.pd | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 ff/ff-autocenter-help.pd create mode 100644 ff/ff-constant-help.pd create mode 100644 ff/ff-gain-help.pd create mode 100644 ff/ff-periodic-help.pd create mode 100644 ff/ff-spring-help.pd diff --git a/ff/ff-autocenter-help.pd b/ff/ff-autocenter-help.pd new file mode 100644 index 0000000..323afd8 --- /dev/null +++ b/ff/ff-autocenter-help.pd @@ -0,0 +1,9 @@ +#N canvas 393 404 450 300 10; +#X text 30 34 sets the amount of "autocentering" of the force-feedback +joystick. Range is [0 \, 1]. 0 is no auto-centering; +#X msg 48 141 0.5; +#X obj 48 191 ff-autocenter 0 0; +#X text 29 69 creation arguments are the device number (starting at +0) and autocenter amount. This affects all effects for that device +; +#X connect 1 0 2 0; diff --git a/ff/ff-constant-help.pd b/ff/ff-constant-help.pd new file mode 100644 index 0000000..48a8fb7 --- /dev/null +++ b/ff/ff-constant-help.pd @@ -0,0 +1,39 @@ +#N canvas 161 237 742 413 10; +#X msg 68 150 bang; +#X msg 44 213 stop; +#X floatatom 301 269 5 0 0 0 - - -; +#X floatatom 187 214 5 0 0 0 - - -; +#X text 185 196 direction in degrees; +#X floatatom 244 249 5 0 0 0 - - -; +#X text 340 264 level \, range = [-1 \, 1]; +#X text 7 130 start the effect; +#X text 12 146 with a; +#X msg 131 77 delay 250; +#X msg 131 48 interval 500; +#X text 229 79 delay before starting; +#X text 229 50 minimum time between triggers; +#X obj 131 290 ff-constant 0 45 1000 0.5; +#X text 107 314 arguments are inputdevice-number \, direction \, duration +and level; +#X msg 131 151 load; +#X msg 131 175 unload; +#X text 191 150 a load message \, uploads an effect to the stick; +#X text 190 175 an unload message \, removes it; +#X text 303 110 startlevel attack-duration (ms) endlevel decay-duration +; +#X msg 131 112 envelope 0 500 0.5 100; +#X text 300 125 levels are in the range [0 \, 1].; +#X text 109 352 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X text 241 221 duration in ms \, 0 is infinite \, this includes the +attack/decay times; +#X connect 0 0 13 0; +#X connect 1 0 13 0; +#X connect 2 0 13 3; +#X connect 3 0 13 1; +#X connect 5 0 13 2; +#X connect 9 0 13 0; +#X connect 10 0 13 0; +#X connect 15 0 13 0; +#X connect 16 0 13 0; +#X connect 20 0 13 0; diff --git a/ff/ff-gain-help.pd b/ff/ff-gain-help.pd new file mode 100644 index 0000000..94b1008 --- /dev/null +++ b/ff/ff-gain-help.pd @@ -0,0 +1,8 @@ +#N canvas 0 0 450 300 10; +#X text 26 62 sets the overall gain [0 \, 1] of the force-feedback +joystick on the device.; +#X msg 74 182 0.3; +#X obj 74 222 ff-gain 0 0.5; +#X text 24 105 creation arguments are the device-number (starting at +0) and gain. This effects all effects for that device; +#X connect 1 0 2 0; diff --git a/ff/ff-periodic-help.pd b/ff/ff-periodic-help.pd new file mode 100644 index 0000000..f280692 --- /dev/null +++ b/ff/ff-periodic-help.pd @@ -0,0 +1,44 @@ +#N canvas 155 183 711 418 10; +#X msg 27 211 bang; +#X msg 3 274 stop; +#X floatatom 340 294 5 0 0 0 - - -; +#X msg 87 12 waveform sine; +#X msg 87 35 period 400; +#X msg 87 86 phase 90; +#X msg 87 60 offset 0.25; +#X text 192 13 square|sine|triangle|saw_up|saw_down; +#X text 192 35 period time in ms (defaults 1000 ms); +#X text 194 59 waveform offset from center [-1 \, 1] (defaults 0=centered) +; +#X floatatom 169 234 5 0 0 0 - - -; +#X text 164 210 direction in degrees; +#X floatatom 257 263 5 0 0 0 - - -; +#X text 338 274 level \, range = [-1 \, 1]; +#X text 255 89 waveform phase in degrees; +#X text -34 191 start the effect; +#X text -29 207 with a; +#X msg 87 139 delay 250; +#X msg 87 113 interval 500; +#X text 255 143 delay before starting; +#X text 257 114 minimum time between triggers; +#X obj 87 329 ff-periodic 0 0 0 0.5; +#X text 90 354 arguments are device-number \, duration and level; +#X msg 87 168 envelope 0 1000 0 100; +#X text 259 160 startlevel attack-duration endlevel decay-duration +levels or in the range [0 \, 1]; +#X text 254 226 duration in ms \, 0 is infinite \, this includes the +attack/decay times; +#X text 90 370 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X connect 0 0 21 0; +#X connect 1 0 21 0; +#X connect 2 0 21 3; +#X connect 3 0 21 0; +#X connect 4 0 21 0; +#X connect 5 0 21 0; +#X connect 6 0 21 0; +#X connect 10 0 21 1; +#X connect 12 0 21 2; +#X connect 17 0 21 0; +#X connect 18 0 21 0; +#X connect 23 0 21 0; diff --git a/ff/ff-spring-help.pd b/ff/ff-spring-help.pd new file mode 100644 index 0000000..980ff2c --- /dev/null +++ b/ff/ff-spring-help.pd @@ -0,0 +1,65 @@ +#N canvas 173 83 685 588 10; +#X msg 46 262 bang; +#X msg 102 261 stop; +#X text 39 242 with a; +#X msg 141 129 delay 250; +#X msg 141 104 interval 500; +#X text 275 130 delay before starting; +#X text 239 104 minimum time between triggers; +#X text 292 192 coefficients that determine how fast; +#X text 292 204 the effect increases in that direction; +#X text 292 215 range = [-1 \, 1]; +#X text 261 279 width of the dead-zone \, where there is no effect +; +#X text 261 303 range is (like the joystick output) [-32768 \, 32767] +; +#X text 262 290 one for each axis; +#X text 262 332 position of the dead-zone in the joystick range; +#X text 262 344 one for each axis; +#X text 262 356 range is also [-32768 \, 32767]; +#X floatatom 204 411 5 0 0 0 - - -; +#X floatatom 331 458 5 0 0 0 - - -; +#X floatatom 267 458 5 0 0 0 - - -; +#X text 200 388 duration in ms \, 0 is infinite; +#X floatatom 394 458 5 0 0 0 - - -; +#X floatatom 458 461 5 0 0 0 - - -; +#X text 267 422 levels \, range = [0 \, 1]; +#X text 266 439 right; +#X text 332 438 left; +#X text 392 438 up; +#X text 458 439 down; +#X text 34 229 start; +#X text 4 79 ff-friction has the same methods; +#X text 5 33 ff-spring is a "conditional effect".; +#X obj 141 484 ff-spring 0 2000 0.5 0.5 0 0.1; +#X text 141 507 creation arguments are device-number \, duration right- +\, left- \, up- and down-level; +#X msg 141 281 deadband-x 1200; +#X msg 141 306 deadband-y 300; +#X msg 141 335 center-x 0; +#X msg 141 358 center-y 20000; +#X msg 141 195 left-coeff 1; +#X msg 141 173 right-coeff 1; +#X msg 141 219 up-coeff -0.7; +#X msg 141 242 down-coeff -1; +#X text 6 49 these effects set up 2 axes (x and y) and you specify +the parameters for each direction.; +#X text 139 540 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X connect 0 0 30 0; +#X connect 1 0 30 0; +#X connect 3 0 30 0; +#X connect 4 0 30 0; +#X connect 16 0 30 1; +#X connect 17 0 30 3; +#X connect 18 0 30 2; +#X connect 20 0 30 4; +#X connect 21 0 30 5; +#X connect 32 0 30 0; +#X connect 33 0 30 0; +#X connect 34 0 30 0; +#X connect 35 0 30 0; +#X connect 36 0 30 0; +#X connect 37 0 30 0; +#X connect 38 0 30 0; +#X connect 39 0 30 0; -- cgit v1.2.1 From d57786814b259a2008811c8c7f7d1039a9ac5282 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 23 May 2004 16:13:11 +0000 Subject: updated enhanced help patches to work with new lib svn path=/trunk/externals/ff/; revision=1760 --- ff/ff-autocenter-help.pd | 26 ++++-- ff/ff-constant-help.pd | 143 +++++++++++++++++++++++--------- ff/ff-friction-help.pd | 154 ++++++++++++++++++++++++++++++++++ ff/ff-gain-help.pd | 23 ++++-- ff/ff-periodic-help.pd | 188 +++++++++++++++++++++++++++++++---------- ff/ff-spring-help.pd | 211 +++++++++++++++++++++++++++++++++-------------- 6 files changed, 590 insertions(+), 155 deletions(-) create mode 100644 ff/ff-friction-help.pd diff --git a/ff/ff-autocenter-help.pd b/ff/ff-autocenter-help.pd index 323afd8..91e9f7e 100644 --- a/ff/ff-autocenter-help.pd +++ b/ff/ff-autocenter-help.pd @@ -1,9 +1,19 @@ -#N canvas 393 404 450 300 10; -#X text 30 34 sets the amount of "autocentering" of the force-feedback +#N canvas 205 279 460 360 10; +#X text 20 66 sets the amount of "autocentering" of the force-feedback joystick. Range is [0 \, 1]. 0 is no auto-centering; -#X msg 48 141 0.5; -#X obj 48 191 ff-autocenter 0 0; -#X text 29 69 creation arguments are the device number (starting at -0) and autocenter amount. This affects all effects for that device -; -#X connect 1 0 2 0; +#X floatatom 77 254 5 0 0 0 - - -; +#X obj 80 226 hsl 225 17 0 1 0 0 empty empty auto-center 25 9 1 12 +-261689 -1 -1 0 0; +#X text 19 149 This is affected by the overall gain \, which can be +controlled used [ff-gain].; +#X obj 4 4 cnv 15 450 30 empty empty [ff-autocenter] 4 12 1 18 -261689 +-1 0; +#X text 19 102 creation arguments are device number (i.e. 0 for /dev/input/event0) +and autocenter amount. This effects all effects for that device; +#X obj 77 277 ff-autocenter 0 0; +#X obj 303 323 all_about_haptics; +#X text 190 325 For more info:; +#X msg 77 197 0.5; +#X connect 1 0 6 0; +#X connect 2 0 1 0; +#X connect 9 0 2 0; diff --git a/ff/ff-constant-help.pd b/ff/ff-constant-help.pd index 48a8fb7..3a06f2b 100644 --- a/ff/ff-constant-help.pd +++ b/ff/ff-constant-help.pd @@ -1,39 +1,108 @@ -#N canvas 161 237 742 413 10; -#X msg 68 150 bang; -#X msg 44 213 stop; -#X floatatom 301 269 5 0 0 0 - - -; -#X floatatom 187 214 5 0 0 0 - - -; -#X text 185 196 direction in degrees; -#X floatatom 244 249 5 0 0 0 - - -; -#X text 340 264 level \, range = [-1 \, 1]; -#X text 7 130 start the effect; -#X text 12 146 with a; -#X msg 131 77 delay 250; -#X msg 131 48 interval 500; -#X text 229 79 delay before starting; -#X text 229 50 minimum time between triggers; -#X obj 131 290 ff-constant 0 45 1000 0.5; -#X text 107 314 arguments are inputdevice-number \, direction \, duration -and level; -#X msg 131 151 load; -#X msg 131 175 unload; -#X text 191 150 a load message \, uploads an effect to the stick; -#X text 190 175 an unload message \, removes it; -#X text 303 110 startlevel attack-duration (ms) endlevel decay-duration +#N canvas 284 83 862 620 10; +#X msg 104 432 bang; +#X msg 68 521 stop; +#X text 383 323 startlevel attack-duration endlevel decay-duration ; -#X msg 131 112 envelope 0 500 0.5 100; -#X text 300 125 levels are in the range [0 \, 1].; -#X text 109 352 the outlet gives the effect number on the device or +#X text 416 438 direction in degrees; +#X text 464 478 duration in ms \, 0 is infinite; +#X text 525 524 level \, range = [-1 \, 1]; +#X text 39 417 start the effect; +#X text 44 433 with a; +#X text 224 150 delay before starting; +#X text 122 75 minimum time between triggers; +#X msg 232 329 envelope 0 100 0 100; +#X obj 218 555 ff-constant 0 0 500 0.5; +#X obj 476 502 hsl 190 17 -1 1 0 0 empty empty level 5 9 1 9 -261689 +-1 -1 0 0; +#X obj 367 418 hsl 175 17 0 360 0 1 empty empty direction 5 9 1 9 -262131 +-1 -1 1900 0; +#X obj 418 458 hsl 235 17 0 5000 0 0 empty empty duration 5 9 1 9 -261681 +-1 -1 0 0; +#X text 385 336 levels are in the range [-1 \, 1]; +#X obj 35 49 hsl 290 17 1 5000 0 1 empty empty interval 25 9 1 12 -225271 +-1 -1 2890 0; +#X msg 32 86 interval \$1; +#X msg 143 154 delay \$1; +#X obj 146 118 hsl 230 17 0 5000 0 1 empty empty delay 25 9 1 12 -228992 +-1 -1 1145 0; +#X obj 100 487 bng 25 250 50 0 empty empty empty 0 -6 0 8 -24198 -1 +-1; +#X obj 68 487 bng 25 250 50 0 empty empty empty 0 -6 0 8 -258699 -1 +-1; +#X obj 364 438 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 39.3103 256; +#X obj 415 480 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 473 524 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 143 138 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 250 256; +#X obj 32 69 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 500.9 256; +#X text 239 13 -- control a force-feedback constant force effect; +#X msg 218 307 envelope \$1 \$2 \$3 \$4; +#X obj 348 228 hsl 200 17 0 1 0 1 empty empty end_level 25 8 1 12 -261689 +-1 -1 0 0; +#X obj 221 186 hsl 200 17 0 1 0 1 empty empty start_level 25 8 1 12 +-261689 -1 -1 11200 0; +#X obj 218 269 nbx 3 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0.562814 256; +#X obj 218 286 pack float float float float; +#X obj 345 269 nbx 3 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 129 10 -233017 -1 -1 0 256; +#X obj 281 269 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 129 10 -233017 -1 -1 0 256; +#X obj 409 269 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 129 10 -233017 -1 -1 0 256; +#X obj 284 207 hsl 235 17 5 5000 1 0 empty empty attack_duration 25 +9 1 12 -261681 -1 -1 0 0; +#X obj 412 249 hsl 235 17 5 5000 1 0 empty empty decay_duration 25 +9 1 12 -261681 -1 -1 0 0; +#X obj 198 269 bng 15 250 50 0 empty pack_bang_env empty 0 -6 64 8 +-262144 -1 -1; +#X obj 3 3 cnv 15 850 30 empty empty [ff-constant] 15 15 1 18 -262131 +-1 0; +#X obj 642 111 all_about_haptics; +#X text 530 110 For more info:; +#X text 394 556 <-- arguments are: device# direction duration level +; +#X text 258 578 the outlet gives the effect number on the device or -1 if it is not loaded.; -#X text 241 221 duration in ms \, 0 is infinite \, this includes the -attack/decay times; -#X connect 0 0 13 0; -#X connect 1 0 13 0; -#X connect 2 0 13 3; -#X connect 3 0 13 1; -#X connect 5 0 13 2; -#X connect 9 0 13 0; -#X connect 10 0 13 0; -#X connect 15 0 13 0; -#X connect 16 0 13 0; -#X connect 20 0 13 0; +#X floatatom 218 584 5 0 0 0 - - -; +#X msg 276 364 load; +#X msg 276 386 unload; +#X text 336 363 a load message \, uploads an effect to the stick; +#X text 335 386 an unload message \, removes it; +#X text 420 58 [ff-constant] sets up a constant force in one direction. +; +#X connect 0 0 11 0; +#X connect 1 0 11 0; +#X connect 10 0 11 0; +#X connect 11 0 44 0; +#X connect 12 0 24 0; +#X connect 13 0 22 0; +#X connect 14 0 23 0; +#X connect 16 0 26 0; +#X connect 17 0 11 0; +#X connect 18 0 11 0; +#X connect 19 0 25 0; +#X connect 20 0 11 0; +#X connect 21 0 1 0; +#X connect 22 0 11 1; +#X connect 23 0 11 2; +#X connect 24 0 11 3; +#X connect 25 0 18 0; +#X connect 26 0 17 0; +#X connect 28 0 11 0; +#X connect 29 0 33 0; +#X connect 30 0 31 0; +#X connect 31 0 32 0; +#X connect 32 0 28 0; +#X connect 33 0 32 2; +#X connect 34 0 32 1; +#X connect 35 0 32 3; +#X connect 36 0 34 0; +#X connect 37 0 35 0; +#X connect 38 0 32 0; +#X connect 45 0 11 0; +#X connect 46 0 11 0; diff --git a/ff/ff-friction-help.pd b/ff/ff-friction-help.pd new file mode 100644 index 0000000..e7b20f3 --- /dev/null +++ b/ff/ff-friction-help.pd @@ -0,0 +1,154 @@ +#N canvas 335 29 859 661 10; +#X text 334 195 coefficients that determine how fast; +#X text 334 207 the effect increases in that direction; +#X text 334 218 range = [-1 \, 1]; +#X text 349 301 width of the dead-zone \, where there is no effect +; +#X text 349 326 range is (like the joystick output) [-32768 \, 32767] +; +#X text 350 312 one for each axis; +#X text 356 424 position of the dead-zone in the joystick range; +#X text 356 436 one for each axis; +#X text 356 448 range is also [-32768 \, 32767]; +#X text 366 526 duration in ms \, 0 is infinite; +#X text 531 555 levels \, range = [0 \, 1]; +#X text 398 74 these effects set up 2 axis (x and y) and you specify +the parameters for each direction.; +#X obj 474 556 hsl 40 15 0 1 0 0 empty empty down 5 8 1 11 -261689 +-1 -1 0 0; +#X obj 420 556 hsl 40 15 0 1 0 0 empty empty up 5 8 1 11 -261689 -1 +-1 0 0; +#X obj 367 556 hsl 40 15 0 1 0 0 empty empty left 5 8 1 11 -261689 +-1 -1 0 0; +#X obj 313 556 hsl 40 15 0 1 0 0 empty empty right 5 8 1 11 -261689 +-1 -1 0 0; +#X msg 260 483 center-y \$1; +#X msg 255 429 center-x \$1; +#X obj 263 450 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 +1 11 -228992 -1 -1 5958 0; +#X obj 258 396 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 +1 11 -228992 -1 -1 3700 0; +#X obj 248 340 hsl 75 15 -32767 32767 0 1 empty empty deadband-y 5 +8 1 11 -225280 -1 -1 3734 0; +#X msg 245 373 deadband-y \$1; +#X msg 242 317 deadband-x \$1; +#X obj 245 284 hsl 75 15 -32767 32767 0 1 empty empty deadband-x 5 +8 1 11 -225280 -1 -1 3836 0; +#X msg 226 258 down-coeff \$1; +#X obj 229 225 hsl 90 15 -1 1 0 1 empty empty down-coeff 5 8 1 11 -257472 +-1 -1 0 0; +#X obj 223 170 hsl 90 15 -1 1 0 1 empty empty up-coeff 5 7 1 11 -257472 +-1 -1 1335 0; +#X obj 120 225 hsl 90 15 -1 1 0 0 empty empty left-coeff 5 7 1 11 -257472 +-1 -1 0 0; +#X obj 103 170 hsl 90 15 -1 1 0 1 empty empty right-coeff 5 7 1 10 +-257472 -1 -1 8900 0; +#X msg 220 203 up-coeff \$1; +#X msg 117 258 left-coeff \$1; +#X msg 100 203 right-coeff \$1; +#X obj 471 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 417 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 364 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 310 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 312 505 hsl 245 17 0 5000 0 0 empty empty duration 25 9 1 12 +-261681 -1 -1 0 0; +#X obj 309 527 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X text 213 14 -- control force-feedback friction effect; +#X obj 195 599 ff-friction 1 2000 0.5 0.5 0 0.1; +#X msg 93 503 bang; +#X msg 84 582 stop; +#X text 32 483 start the effect; +#X text 37 499 with a; +#X obj 85 533 bng 25 250 50 0 empty empty empty 0 -6 0 8 -24198 -1 +-1; +#X obj 53 533 bng 25 250 50 0 empty empty empty 0 -6 0 8 -258699 -1 +-1; +#X text 141 140 delay before starting; +#X text 111 69 minimum time between triggers; +#X obj 24 43 hsl 290 17 0 5000 0 1 empty empty interval 25 9 1 12 -225271 +-1 -1 2890 0; +#X msg 21 80 interval \$1; +#X msg 60 144 delay \$1; +#X obj 63 108 hsl 230 17 0 5000 0 1 empty empty delay 25 9 1 12 -228992 +-1 -1 1145 0; +#X obj 60 128 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 250 256; +#X obj 21 63 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 500 256; +#X obj 100 187 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 1 256; +#X obj 117 242 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 226 242 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 -1 256; +#X obj 220 187 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 -0.7 256; +#X obj 242 301 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 1204.41 256; +#X obj 245 357 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 301.102 256; +#X obj 255 413 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 260 467 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 19996.7 256; +#X obj 3 3 cnv 15 850 30 empty empty [ff-friction] 15 15 1 18 -257472 +-1 0; +#X obj 568 135 all_about_haptics; +#X text 456 134 For more info:; +#X text 428 599 arguments are: device# duration right- left- up- down-level +; +#X text 238 619 the outlet gives the effect number on the device or +-1 if it is not loaded.; +#X floatatom 195 624 5 0 0 0 - - -; +#X text 397 58 [ff-friction] is a "conditional effect".; +#X text 396 110 [ff-spring] has the same methods; +#X connect 12 0 32 0; +#X connect 13 0 33 0; +#X connect 14 0 34 0; +#X connect 15 0 35 0; +#X connect 16 0 39 0; +#X connect 17 0 39 0; +#X connect 18 0 61 0; +#X connect 19 0 60 0; +#X connect 20 0 59 0; +#X connect 21 0 39 0; +#X connect 22 0 39 0; +#X connect 23 0 58 0; +#X connect 24 0 39 0; +#X connect 25 0 56 0; +#X connect 26 0 57 0; +#X connect 27 0 55 0; +#X connect 28 0 54 0; +#X connect 29 0 39 0; +#X connect 30 0 39 0; +#X connect 31 0 39 0; +#X connect 32 0 39 5; +#X connect 33 0 39 4; +#X connect 34 0 39 3; +#X connect 35 0 39 2; +#X connect 36 0 37 0; +#X connect 37 0 39 1; +#X connect 39 0 67 0; +#X connect 40 0 39 0; +#X connect 41 0 39 0; +#X connect 44 0 39 0; +#X connect 45 0 41 0; +#X connect 48 0 53 0; +#X connect 49 0 39 0; +#X connect 50 0 39 0; +#X connect 51 0 52 0; +#X connect 52 0 50 0; +#X connect 53 0 49 0; +#X connect 54 0 31 0; +#X connect 55 0 30 0; +#X connect 56 0 24 0; +#X connect 57 0 29 0; +#X connect 58 0 22 0; +#X connect 59 0 21 0; +#X connect 60 0 17 0; +#X connect 61 0 16 0; diff --git a/ff/ff-gain-help.pd b/ff/ff-gain-help.pd index 94b1008..e82e005 100644 --- a/ff/ff-gain-help.pd +++ b/ff/ff-gain-help.pd @@ -1,8 +1,17 @@ -#N canvas 0 0 450 300 10; -#X text 26 62 sets the overall gain [0 \, 1] of the force-feedback +#N canvas 607 32 460 364 10; +#X floatatom 123 231 5 0 0 0 - - -; +#X obj 126 205 hsl 195 17 0 1 0 0 empty empty gain 25 8 1 12 -261689 +-1 -1 17460 0; +#X obj 3 3 cnv 15 450 30 empty empty [ff-gain] 4 12 1 18 -261689 -1 +0; +#X obj 123 254 ff-gain 0 0.5; +#X obj 320 326 all_about_haptics; +#X text 214 326 For more info:; +#X msg 123 178 0.9; +#X text 24 102 Creation arguments are device number (i.e. 0 for /dev/input/event0) +and gain. This affects all effects for that device.; +#X text 24 64 Sets the overall gain \, between 0 and 1 \, of the force-feedback joystick on the device.; -#X msg 74 182 0.3; -#X obj 74 222 ff-gain 0 0.5; -#X text 24 105 creation arguments are the device-number (starting at -0) and gain. This effects all effects for that device; -#X connect 1 0 2 0; +#X connect 0 0 3 0; +#X connect 1 0 0 0; +#X connect 6 0 1 0; diff --git a/ff/ff-periodic-help.pd b/ff/ff-periodic-help.pd index f280692..52a833b 100644 --- a/ff/ff-periodic-help.pd +++ b/ff/ff-periodic-help.pd @@ -1,44 +1,148 @@ -#N canvas 155 183 711 418 10; -#X msg 27 211 bang; -#X msg 3 274 stop; -#X floatatom 340 294 5 0 0 0 - - -; -#X msg 87 12 waveform sine; -#X msg 87 35 period 400; -#X msg 87 86 phase 90; -#X msg 87 60 offset 0.25; -#X text 192 13 square|sine|triangle|saw_up|saw_down; -#X text 192 35 period time in ms (defaults 1000 ms); -#X text 194 59 waveform offset from center [-1 \, 1] (defaults 0=centered) +#N canvas 289 81 857 641 10; +#X msg 65 474 bang; +#X msg 66 556 stop; +#X msg 459 386 envelope 0 100 0 100; +#X text 85 71 period time in ms (defaults 1000 ms); +#X text 477 407 startlevel attack-duration endlevel decay-duration ; -#X floatatom 169 234 5 0 0 0 - - -; -#X text 164 210 direction in degrees; -#X floatatom 257 263 5 0 0 0 - - -; -#X text 338 274 level \, range = [-1 \, 1]; -#X text 255 89 waveform phase in degrees; -#X text -34 191 start the effect; -#X text -29 207 with a; -#X msg 87 139 delay 250; -#X msg 87 113 interval 500; -#X text 255 143 delay before starting; -#X text 257 114 minimum time between triggers; -#X obj 87 329 ff-periodic 0 0 0 0.5; -#X text 90 354 arguments are device-number \, duration and level; -#X msg 87 168 envelope 0 1000 0 100; -#X text 259 160 startlevel attack-duration endlevel decay-duration -levels or in the range [0 \, 1]; -#X text 254 226 duration in ms \, 0 is infinite \, this includes the -attack/decay times; -#X text 90 370 the outlet gives the effect number on the device or +#X text 188 204 waveform phase in degrees; +#X text 10 458 start the effect; +#X text 15 474 with a; +#X obj 319 573 ff-periodic 1 0 0 0.5; +#X text 505 473 direction in degrees; +#X text 547 511 duration in ms \, 0 is infinite; +#X text 625 554 level \, range = [-1 \, 1]; +#X obj 576 532 hsl 190 17 -1 1 0 0 empty empty level 25 9 1 12 -261689 +-1 -1 0 0; +#X obj 456 453 hsl 175 17 0 360 0 0 empty empty direction 25 9 1 12 +-262131 -1 -1 0 0; +#X obj 491 491 hsl 245 17 0 5000 0 0 empty empty duration 25 9 1 12 +-261681 -1 -1 0 0; +#X obj 453 473 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 488 513 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 573 554 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X text 250 12 -- control a force-feedback periodic force effect; +#X obj 67 507 bng 25 250 50 0 empty empty empty 0 -6 0 8 -24198 -1 +-1; +#X obj 35 507 bng 25 250 50 0 empty empty empty 0 -6 0 8 -258699 -1 +-1; +#X text 228 272 delay before starting; +#X obj 216 316 hsl 200 17 0 5000 0 1 empty empty interval 25 9 1 12 +-225271 -1 -1 2000 0; +#X msg 213 353 interval \$1; +#X msg 175 289 delay \$1; +#X obj 178 253 hsl 200 17 0 5000 0 1 empty empty delay 25 9 1 12 -228992 +-1 -1 1000 0; +#X obj 175 273 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 251.256 256; +#X obj 213 336 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 502.513 256; +#X msg 134 223 phase \$1; +#X obj 137 184 hsl 220 17 0 360 0 1 empty empty phase 25 9 1 12 -257472 +-1 -1 5500 0; +#X obj 134 205 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 90.411 256; +#X msg 90 157 offset \$1; +#X obj 93 117 hsl 220 17 -1 1 0 1 empty empty offset 25 9 1 12 -225280 +-1 -1 13700 0; +#X obj 90 139 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0.251142 256; +#X msg 30 92 period \$1; +#X obj 33 51 hsl 300 17 2 2000 1 1 empty empty period 25 9 1 12 -261681 +-1 -1 22900 0; +#X obj 30 73 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 396.907 256; +#X msg 85 429 waveform \$1; +#X msg 40 262 square; +#X msg 51 282 sine; +#X msg 61 302 triangle; +#X msg 70 322 saw_up; +#X msg 77 342 saw_down; +#X obj 85 375 symbol; +#X text 8 244 waveform shape; +#X symbolatom 85 408 9 0 0 0 current: - -; +#X msg 459 354 envelope \$1 \$2 \$3 \$4; +#X obj 589 275 hsl 150 17 0 1 0 0 empty empty end_level 25 8 1 12 -261689 +-1 -1 0 0; +#X obj 462 233 hsl 150 17 0 1 0 0 empty empty start_level 25 8 1 12 +-261689 -1 -1 0 0; +#X obj 459 316 nbx 3 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 459 333 pack float float float float; +#X obj 586 316 nbx 3 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 129 10 -233017 -1 -1 0 256; +#X obj 522 316 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 129 10 -233017 -1 -1 1027.59 256; +#X obj 650 316 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 129 10 -233017 -1 -1 101.445 256; +#X obj 525 254 hsl 180 17 5 5000 1 1 empty empty attack_duration 25 +9 1 12 -261681 -1 -1 13800 0; +#X obj 653 296 hsl 180 17 5 5000 1 1 empty empty decay_duration 25 +9 1 12 -261681 -1 -1 7800 0; +#X obj 440 316 bng 15 250 50 0 empty pack_bang_env empty 0 -6 64 8 +-262144 -1 -1; +#X obj 3 2 cnv 15 850 30 empty empty [ff-periodic] 15 15 1 18 -261681 +-1 0; +#X text 480 573 <-- arguments are: device# direction duration level +; +#X text 360 596 the outlet gives the effect number on the device or -1 if it is not loaded.; -#X connect 0 0 21 0; -#X connect 1 0 21 0; -#X connect 2 0 21 3; -#X connect 3 0 21 0; -#X connect 4 0 21 0; -#X connect 5 0 21 0; -#X connect 6 0 21 0; -#X connect 10 0 21 1; -#X connect 12 0 21 2; -#X connect 17 0 21 0; -#X connect 18 0 21 0; -#X connect 23 0 21 0; +#X floatatom 319 603 5 0 0 0 - - -; +#X text 554 107 For more info:; +#X obj 663 106 all_about_haptics; +#X text 300 335 minimum time; +#X text 300 350 between triggers; +#X text 422 56 [ff-periodic] generates a periodic force \, basically +a waveform that can be a pulsing or a vibration depending on the "period". +; +#X text 145 139 waveform offset from center [-1 \, 1]; +#X text 199 155 (defaults 0=centered); +#X connect 0 0 8 0; +#X connect 1 0 8 0; +#X connect 2 0 8 0; +#X connect 8 0 60 0; +#X connect 12 0 17 0; +#X connect 13 0 15 0; +#X connect 14 0 16 0; +#X connect 15 0 8 1; +#X connect 16 0 8 2; +#X connect 17 0 8 3; +#X connect 19 0 8 0; +#X connect 20 0 1 0; +#X connect 22 0 27 0; +#X connect 23 0 8 0; +#X connect 24 0 8 0; +#X connect 25 0 26 0; +#X connect 26 0 24 0; +#X connect 27 0 23 0; +#X connect 28 0 8 0; +#X connect 29 0 30 0; +#X connect 30 0 28 0; +#X connect 31 0 8 0; +#X connect 32 0 33 0; +#X connect 33 0 31 0; +#X connect 34 0 8 0; +#X connect 35 0 36 0; +#X connect 36 0 34 0; +#X connect 37 0 8 0; +#X connect 38 0 43 0; +#X connect 39 0 43 0; +#X connect 40 0 43 0; +#X connect 41 0 43 0; +#X connect 42 0 43 0; +#X connect 43 0 45 0; +#X connect 45 0 37 0; +#X connect 46 0 8 0; +#X connect 47 0 51 0; +#X connect 48 0 49 0; +#X connect 49 0 50 0; +#X connect 50 0 46 0; +#X connect 51 0 50 2; +#X connect 52 0 50 1; +#X connect 53 0 50 3; +#X connect 54 0 52 0; +#X connect 55 0 53 0; +#X connect 56 0 50 0; diff --git a/ff/ff-spring-help.pd b/ff/ff-spring-help.pd index 980ff2c..7e82ea6 100644 --- a/ff/ff-spring-help.pd +++ b/ff/ff-spring-help.pd @@ -1,65 +1,154 @@ -#N canvas 173 83 685 588 10; -#X msg 46 262 bang; -#X msg 102 261 stop; -#X text 39 242 with a; -#X msg 141 129 delay 250; -#X msg 141 104 interval 500; -#X text 275 130 delay before starting; -#X text 239 104 minimum time between triggers; -#X text 292 192 coefficients that determine how fast; -#X text 292 204 the effect increases in that direction; -#X text 292 215 range = [-1 \, 1]; -#X text 261 279 width of the dead-zone \, where there is no effect +#N canvas 335 29 859 661 10; +#X text 334 195 coefficients that determine how fast; +#X text 334 207 the effect increases in that direction; +#X text 334 218 range = [-1 \, 1]; +#X text 349 301 width of the dead-zone \, where there is no effect ; -#X text 261 303 range is (like the joystick output) [-32768 \, 32767] +#X text 349 326 range is (like the joystick output) [-32768 \, 32767] ; -#X text 262 290 one for each axis; -#X text 262 332 position of the dead-zone in the joystick range; -#X text 262 344 one for each axis; -#X text 262 356 range is also [-32768 \, 32767]; -#X floatatom 204 411 5 0 0 0 - - -; -#X floatatom 331 458 5 0 0 0 - - -; -#X floatatom 267 458 5 0 0 0 - - -; -#X text 200 388 duration in ms \, 0 is infinite; -#X floatatom 394 458 5 0 0 0 - - -; -#X floatatom 458 461 5 0 0 0 - - -; -#X text 267 422 levels \, range = [0 \, 1]; -#X text 266 439 right; -#X text 332 438 left; -#X text 392 438 up; -#X text 458 439 down; -#X text 34 229 start; -#X text 4 79 ff-friction has the same methods; -#X text 5 33 ff-spring is a "conditional effect".; -#X obj 141 484 ff-spring 0 2000 0.5 0.5 0 0.1; -#X text 141 507 creation arguments are device-number \, duration right- -\, left- \, up- and down-level; -#X msg 141 281 deadband-x 1200; -#X msg 141 306 deadband-y 300; -#X msg 141 335 center-x 0; -#X msg 141 358 center-y 20000; -#X msg 141 195 left-coeff 1; -#X msg 141 173 right-coeff 1; -#X msg 141 219 up-coeff -0.7; -#X msg 141 242 down-coeff -1; -#X text 6 49 these effects set up 2 axes (x and y) and you specify +#X text 350 312 one for each axis; +#X text 356 424 position of the dead-zone in the joystick range; +#X text 356 436 one for each axis; +#X text 356 448 range is also [-32768 \, 32767]; +#X text 366 526 duration in ms \, 0 is infinite; +#X text 531 555 levels \, range = [0 \, 1]; +#X text 398 74 these effects set up 2 axis (x and y) and you specify the parameters for each direction.; -#X text 139 540 the outlet gives the effect number on the device or +#X obj 474 556 hsl 40 15 0 1 0 0 empty empty down 5 8 1 11 -261689 +-1 -1 0 0; +#X obj 420 556 hsl 40 15 0 1 0 0 empty empty up 5 8 1 11 -261689 -1 +-1 0 0; +#X obj 367 556 hsl 40 15 0 1 0 0 empty empty left 5 8 1 11 -261689 +-1 -1 0 0; +#X obj 313 556 hsl 40 15 0 1 0 0 empty empty right 5 8 1 11 -261689 +-1 -1 0 0; +#X msg 260 483 center-y \$1; +#X msg 255 429 center-x \$1; +#X obj 263 450 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 +1 11 -228992 -1 -1 5958 0; +#X obj 258 396 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 +1 11 -228992 -1 -1 3700 0; +#X obj 248 340 hsl 75 15 -32767 32767 0 1 empty empty deadband-y 5 +8 1 11 -225280 -1 -1 3734 0; +#X msg 245 373 deadband-y \$1; +#X msg 242 317 deadband-x \$1; +#X obj 245 284 hsl 75 15 -32767 32767 0 1 empty empty deadband-x 5 +8 1 11 -225280 -1 -1 3836 0; +#X msg 226 258 down-coeff \$1; +#X obj 229 225 hsl 90 15 -1 1 0 1 empty empty down-coeff 5 8 1 11 -257472 +-1 -1 0 0; +#X obj 223 170 hsl 90 15 -1 1 0 1 empty empty up-coeff 5 7 1 11 -257472 +-1 -1 1335 0; +#X obj 120 225 hsl 90 15 -1 1 0 0 empty empty left-coeff 5 7 1 11 -257472 +-1 -1 8900 0; +#X obj 103 170 hsl 90 15 -1 1 0 1 empty empty right-coeff 5 7 1 10 +-257472 -1 -1 8900 0; +#X msg 220 203 up-coeff \$1; +#X msg 117 258 left-coeff \$1; +#X msg 100 203 right-coeff \$1; +#X obj 471 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 417 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 364 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 310 575 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 312 505 hsl 245 17 0 5000 0 0 empty empty duration 25 9 1 12 +-261681 -1 -1 0 0; +#X obj 309 527 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X text 213 14 -- control force-feedback spring effect; +#X obj 195 599 ff-spring 1 2000 0.5 0.5 0 0.1; +#X msg 93 503 bang; +#X msg 84 582 stop; +#X text 32 483 start the effect; +#X text 37 499 with a; +#X obj 85 533 bng 25 250 50 0 empty empty empty 0 -6 0 8 -24198 -1 +-1; +#X obj 53 533 bng 25 250 50 0 empty empty empty 0 -6 0 8 -258699 -1 +-1; +#X text 141 140 delay before starting; +#X text 111 69 minimum time between triggers; +#X obj 24 43 hsl 290 17 0 5000 0 1 empty empty interval 25 9 1 12 -225271 +-1 -1 2890 0; +#X msg 21 80 interval \$1; +#X msg 60 144 delay \$1; +#X obj 63 108 hsl 230 17 0 5000 0 1 empty empty delay 25 9 1 12 -228992 +-1 -1 1145 0; +#X obj 60 128 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 250 256; +#X obj 21 63 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 500 256; +#X obj 100 187 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 1 256; +#X obj 117 242 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 1 256; +#X obj 226 242 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 -1 256; +#X obj 220 187 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 -0.7 256; +#X obj 242 301 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 1204.41 256; +#X obj 245 357 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 301.102 256; +#X obj 255 413 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 0 256; +#X obj 260 467 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +-233017 -1 -1 19996.7 256; +#X obj 3 3 cnv 15 850 30 empty empty [ff-spring] 15 15 1 18 -257472 +-1 0; +#X obj 568 135 all_about_haptics; +#X text 456 134 For more info:; +#X text 415 599 arguments are: device# duration right- left- up- down-level +; +#X text 238 619 the outlet gives the effect number on the device or -1 if it is not loaded.; -#X connect 0 0 30 0; -#X connect 1 0 30 0; -#X connect 3 0 30 0; -#X connect 4 0 30 0; -#X connect 16 0 30 1; -#X connect 17 0 30 3; -#X connect 18 0 30 2; -#X connect 20 0 30 4; -#X connect 21 0 30 5; -#X connect 32 0 30 0; -#X connect 33 0 30 0; -#X connect 34 0 30 0; -#X connect 35 0 30 0; -#X connect 36 0 30 0; -#X connect 37 0 30 0; -#X connect 38 0 30 0; -#X connect 39 0 30 0; +#X floatatom 195 624 5 0 0 0 - - -; +#X text 397 58 [ff-spring] is a "conditional effect".; +#X text 396 110 [ff-friction] has the same methods; +#X connect 12 0 32 0; +#X connect 13 0 33 0; +#X connect 14 0 34 0; +#X connect 15 0 35 0; +#X connect 16 0 39 0; +#X connect 17 0 39 0; +#X connect 18 0 61 0; +#X connect 19 0 60 0; +#X connect 20 0 59 0; +#X connect 21 0 39 0; +#X connect 22 0 39 0; +#X connect 23 0 58 0; +#X connect 24 0 39 0; +#X connect 25 0 56 0; +#X connect 26 0 57 0; +#X connect 27 0 55 0; +#X connect 28 0 54 0; +#X connect 29 0 39 0; +#X connect 30 0 39 0; +#X connect 31 0 39 0; +#X connect 32 0 39 5; +#X connect 33 0 39 4; +#X connect 34 0 39 3; +#X connect 35 0 39 2; +#X connect 36 0 37 0; +#X connect 37 0 39 1; +#X connect 39 0 67 0; +#X connect 40 0 39 0; +#X connect 41 0 39 0; +#X connect 44 0 39 0; +#X connect 45 0 41 0; +#X connect 48 0 53 0; +#X connect 49 0 39 0; +#X connect 50 0 39 0; +#X connect 51 0 52 0; +#X connect 52 0 50 0; +#X connect 53 0 49 0; +#X connect 54 0 31 0; +#X connect 55 0 30 0; +#X connect 56 0 24 0; +#X connect 57 0 29 0; +#X connect 58 0 22 0; +#X connect 59 0 21 0; +#X connect 60 0 17 0; +#X connect 61 0 16 0; -- cgit v1.2.1 From ad6b970ca67d8280fe83160335c2b8525f5ddace Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 23 May 2004 16:25:29 +0000 Subject: updated all to use device 0 svn path=/trunk/externals/ff/; revision=1761 --- ff/ff-friction-help.pd | 2 +- ff/ff-periodic-help.pd | 2 +- ff/ff-spring-help.pd | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ff/ff-friction-help.pd b/ff/ff-friction-help.pd index e7b20f3..e169d2d 100644 --- a/ff/ff-friction-help.pd +++ b/ff/ff-friction-help.pd @@ -59,7 +59,7 @@ the parameters for each direction.; #X obj 309 527 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 0 256; #X text 213 14 -- control force-feedback friction effect; -#X obj 195 599 ff-friction 1 2000 0.5 0.5 0 0.1; +#X obj 195 599 ff-friction 0 2000 0.5 0.5 0 0.1; #X msg 93 503 bang; #X msg 84 582 stop; #X text 32 483 start the effect; diff --git a/ff/ff-periodic-help.pd b/ff/ff-periodic-help.pd index 52a833b..afda2de 100644 --- a/ff/ff-periodic-help.pd +++ b/ff/ff-periodic-help.pd @@ -8,7 +8,7 @@ #X text 188 204 waveform phase in degrees; #X text 10 458 start the effect; #X text 15 474 with a; -#X obj 319 573 ff-periodic 1 0 0 0.5; +#X obj 319 573 ff-periodic 0 0 0 0.5; #X text 505 473 direction in degrees; #X text 547 511 duration in ms \, 0 is infinite; #X text 625 554 level \, range = [-1 \, 1]; diff --git a/ff/ff-spring-help.pd b/ff/ff-spring-help.pd index 7e82ea6..462cf4c 100644 --- a/ff/ff-spring-help.pd +++ b/ff/ff-spring-help.pd @@ -59,7 +59,7 @@ the parameters for each direction.; #X obj 309 527 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 0 256; #X text 213 14 -- control force-feedback spring effect; -#X obj 195 599 ff-spring 1 2000 0.5 0.5 0 0.1; +#X obj 195 599 ff-spring 0 2000 0.5 0.5 0 0.1; #X msg 93 503 bang; #X msg 84 582 stop; #X text 32 483 start the effect; -- cgit v1.2.1 From 91b96a1dc7b49d4a803e09b3341ec18ecf6132b3 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 25 May 2004 04:42:16 +0000 Subject: added compiler warnings and fixed most warnings svn path=/trunk/externals/ff/; revision=1765 --- ff/ff.c | 4 +++- ff/makefile | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ff/ff.c b/ff/ff.c index 784b2fe..20cbc4d 100644 --- a/ff/ff.c +++ b/ff/ff.c @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include "input.h" @@ -455,7 +457,7 @@ void ffPeriodic_level(t_ff *x, t_floatarg level) void ffPeriodic_waveform(t_ff *x, t_symbol* waveform) { if (x->ff_fd < 0) return; - unsigned short shortwave; + unsigned short shortwave = 0; int n = 0; while (waves[n].wave) { diff --git a/ff/makefile b/ff/makefile index 99554e3..7708283 100644 --- a/ff/makefile +++ b/ff/makefile @@ -1,7 +1,14 @@ + +CFLAGS = -O2 -W -Wall + +all: ff + ff: ff.c - gcc $(CFLAGS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o ff.o -c ff.c + $(CC) $(CFLAGS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o ff.o -c ff.c ld -export_dynamic -shared -o ff.pd_linux ff.o -lc -lm strip --strip-unneeded ff.pd_linux rm ff.o +clean: + rm -f *~ *.pd_* *.dll *.o -- cgit v1.2.1 From ccda2c902e1ec7b8686c64cf3777322bff61c75b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 26 May 2004 04:42:10 +0000 Subject: updated [load( and [unload( messages svn path=/trunk/externals/ff/; revision=1767 --- ff/ff-constant-help.pd | 28 ++++++++++++++-------------- ff/ff-periodic-help.pd | 42 ++++++++++++++++++++++++------------------ ff/ff-spring-help.pd | 45 +++++++++++++++++++++++++-------------------- 3 files changed, 63 insertions(+), 52 deletions(-) diff --git a/ff/ff-constant-help.pd b/ff/ff-constant-help.pd index 3a06f2b..411ebb5 100644 --- a/ff/ff-constant-help.pd +++ b/ff/ff-constant-help.pd @@ -12,12 +12,12 @@ #X text 122 75 minimum time between triggers; #X msg 232 329 envelope 0 100 0 100; #X obj 218 555 ff-constant 0 0 500 0.5; -#X obj 476 502 hsl 190 17 -1 1 0 0 empty empty level 5 9 1 9 -261689 --1 -1 0 0; -#X obj 367 418 hsl 175 17 0 360 0 1 empty empty direction 5 9 1 9 -262131 --1 -1 1900 0; -#X obj 418 458 hsl 235 17 0 5000 0 0 empty empty duration 5 9 1 9 -261681 --1 -1 0 0; +#X obj 476 502 hsl 190 17 -1 1 0 0 empty empty level 25 9 1 12 -261689 +-1 -1 18900 0; +#X obj 367 418 hsl 175 17 0 360 0 1 empty empty direction 25 9 1 12 +-262131 -1 -1 17400 0; +#X obj 418 458 hsl 235 17 0 5000 0 0 empty empty duration 25 9 1 12 +-261681 -1 -1 17800 0; #X text 385 336 levels are in the range [-1 \, 1]; #X obj 35 49 hsl 290 17 1 5000 0 1 empty empty interval 25 9 1 12 -225271 -1 -1 2890 0; @@ -30,11 +30,11 @@ #X obj 68 487 bng 25 250 50 0 empty empty empty 0 -6 0 8 -258699 -1 -1; #X obj 364 438 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 --233017 -1 -1 39.3103 256; +-233017 -1 -1 360 256; #X obj 415 480 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 --233017 -1 -1 0 256; +-233017 -1 -1 3803.42 256; #X obj 473 524 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 --233017 -1 -1 0 256; +-233017 -1 -1 1 256; #X obj 143 138 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 250 256; #X obj 32 69 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 @@ -49,17 +49,17 @@ -233017 -1 -1 0.562814 256; #X obj 218 286 pack float float float float; #X obj 345 269 nbx 3 14 -1e+37 1e+37 0 0 pack_bang_env empty empty -0 -6 129 10 -233017 -1 -1 0 256; +0 -6 1 10 -233017 -1 -1 0 256; #X obj 281 269 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty -0 -6 129 10 -233017 -1 -1 0 256; +0 -6 1 10 -233017 -1 -1 0 256; #X obj 409 269 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty -0 -6 129 10 -233017 -1 -1 0 256; +0 -6 1 10 -233017 -1 -1 0 256; #X obj 284 207 hsl 235 17 5 5000 1 0 empty empty attack_duration 25 9 1 12 -261681 -1 -1 0 0; #X obj 412 249 hsl 235 17 5 5000 1 0 empty empty decay_duration 25 9 1 12 -261681 -1 -1 0 0; -#X obj 198 269 bng 15 250 50 0 empty pack_bang_env empty 0 -6 64 8 --262144 -1 -1; +#X obj 198 269 bng 15 250 50 0 empty pack_bang_env empty 0 -6 0 8 -262144 +-1 -1; #X obj 3 3 cnv 15 850 30 empty empty [ff-constant] 15 15 1 18 -262131 -1 0; #X obj 642 111 all_about_haptics; diff --git a/ff/ff-periodic-help.pd b/ff/ff-periodic-help.pd index afda2de..a518aea 100644 --- a/ff/ff-periodic-help.pd +++ b/ff/ff-periodic-help.pd @@ -1,9 +1,9 @@ -#N canvas 289 81 857 641 10; +#N canvas 360 67 857 641 10; #X msg 65 474 bang; #X msg 66 556 stop; -#X msg 459 386 envelope 0 100 0 100; +#X msg 453 340 envelope 0 100 0 100; #X text 85 71 period time in ms (defaults 1000 ms); -#X text 477 407 startlevel attack-duration endlevel decay-duration +#X text 471 361 startlevel attack-duration endlevel decay-duration ; #X text 188 204 waveform phase in degrees; #X text 10 458 start the effect; @@ -64,26 +64,26 @@ #X obj 85 375 symbol; #X text 8 244 waveform shape; #X symbolatom 85 408 9 0 0 0 current: - -; -#X msg 459 354 envelope \$1 \$2 \$3 \$4; -#X obj 589 275 hsl 150 17 0 1 0 0 empty empty end_level 25 8 1 12 -261689 +#X msg 453 308 envelope \$1 \$2 \$3 \$4; +#X obj 583 229 hsl 150 17 0 1 0 0 empty empty end_level 25 8 1 12 -261689 -1 -1 0 0; -#X obj 462 233 hsl 150 17 0 1 0 0 empty empty start_level 25 8 1 12 +#X obj 456 187 hsl 150 17 0 1 0 0 empty empty start_level 25 8 1 12 -261689 -1 -1 0 0; -#X obj 459 316 nbx 3 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +#X obj 453 270 nbx 3 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 0 256; -#X obj 459 333 pack float float float float; -#X obj 586 316 nbx 3 14 -1e+37 1e+37 0 0 pack_bang_env empty empty -0 -6 129 10 -233017 -1 -1 0 256; -#X obj 522 316 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty -0 -6 129 10 -233017 -1 -1 1027.59 256; -#X obj 650 316 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty -0 -6 129 10 -233017 -1 -1 101.445 256; -#X obj 525 254 hsl 180 17 5 5000 1 1 empty empty attack_duration 25 +#X obj 453 287 pack float float float float; +#X obj 580 270 nbx 3 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 1 10 -233017 -1 -1 0 256; +#X obj 516 270 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 1 10 -233017 -1 -1 1027.59 256; +#X obj 644 270 nbx 6 14 -1e+37 1e+37 0 0 pack_bang_env empty empty +0 -6 1 10 -233017 -1 -1 101.445 256; +#X obj 519 208 hsl 180 17 5 5000 1 1 empty empty attack_duration 25 9 1 12 -261681 -1 -1 13800 0; -#X obj 653 296 hsl 180 17 5 5000 1 1 empty empty decay_duration 25 +#X obj 647 250 hsl 180 17 5 5000 1 1 empty empty decay_duration 25 9 1 12 -261681 -1 -1 7800 0; -#X obj 440 316 bng 15 250 50 0 empty pack_bang_env empty 0 -6 64 8 --262144 -1 -1; +#X obj 434 270 bng 15 250 50 0 empty pack_bang_env empty 0 -6 0 8 -262144 +-1 -1; #X obj 3 2 cnv 15 850 30 empty empty [ff-periodic] 15 15 1 18 -261681 -1 0; #X text 480 573 <-- arguments are: device# direction duration level @@ -100,6 +100,10 @@ a waveform that can be a pulsing or a vibration depending on the "period". ; #X text 145 139 waveform offset from center [-1 \, 1]; #X text 199 155 (defaults 0=centered); +#X msg 441 392 load; +#X msg 441 416 unload; +#X text 492 391 a load message \, uploads an effect to the stick; +#X text 491 416 an unload message \, removes it; #X connect 0 0 8 0; #X connect 1 0 8 0; #X connect 2 0 8 0; @@ -146,3 +150,5 @@ a waveform that can be a pulsing or a vibration depending on the "period". #X connect 54 0 52 0; #X connect 55 0 53 0; #X connect 56 0 50 0; +#X connect 68 0 8 0; +#X connect 69 0 8 0; diff --git a/ff/ff-spring-help.pd b/ff/ff-spring-help.pd index 462cf4c..c5eaa9a 100644 --- a/ff/ff-spring-help.pd +++ b/ff/ff-spring-help.pd @@ -2,14 +2,14 @@ #X text 334 195 coefficients that determine how fast; #X text 334 207 the effect increases in that direction; #X text 334 218 range = [-1 \, 1]; -#X text 349 301 width of the dead-zone \, where there is no effect +#X text 386 301 width of the dead-zone \, where there is no effect ; -#X text 349 326 range is (like the joystick output) [-32768 \, 32767] +#X text 386 326 range is (like the joystick output) [-32768 \, 32767] ; -#X text 350 312 one for each axis; -#X text 356 424 position of the dead-zone in the joystick range; -#X text 356 436 one for each axis; -#X text 356 448 range is also [-32768 \, 32767]; +#X text 387 312 one for each axis; +#X text 393 424 position of the dead-zone in the joystick range; +#X text 393 436 one for each axis; +#X text 393 448 range is also [-32768 \, 32767]; #X text 366 526 duration in ms \, 0 is infinite; #X text 531 555 levels \, range = [0 \, 1]; #X text 398 74 these effects set up 2 axis (x and y) and you specify @@ -22,17 +22,17 @@ the parameters for each direction.; -1 -1 0 0; #X obj 313 556 hsl 40 15 0 1 0 0 empty empty right 5 8 1 11 -261689 -1 -1 0 0; -#X msg 260 483 center-y \$1; -#X msg 255 429 center-x \$1; -#X obj 263 450 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 +#X msg 297 483 center-y \$1; +#X msg 292 429 center-x \$1; +#X obj 300 450 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 1 11 -228992 -1 -1 5958 0; -#X obj 258 396 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 +#X obj 295 396 hsl 75 15 -32767 32767 0 1 empty empty center-x 5 8 1 11 -228992 -1 -1 3700 0; -#X obj 248 340 hsl 75 15 -32767 32767 0 1 empty empty deadband-y 5 +#X obj 285 340 hsl 75 15 -32767 32767 0 1 empty empty deadband-y 5 8 1 11 -225280 -1 -1 3734 0; -#X msg 245 373 deadband-y \$1; -#X msg 242 317 deadband-x \$1; -#X obj 245 284 hsl 75 15 -32767 32767 0 1 empty empty deadband-x 5 +#X msg 282 373 deadband-y \$1; +#X msg 279 317 deadband-x \$1; +#X obj 282 284 hsl 75 15 -32767 32767 0 1 empty empty deadband-x 5 8 1 11 -225280 -1 -1 3836 0; #X msg 226 258 down-coeff \$1; #X obj 229 225 hsl 90 15 -1 1 0 1 empty empty down-coeff 5 8 1 11 -257472 @@ -40,7 +40,7 @@ the parameters for each direction.; #X obj 223 170 hsl 90 15 -1 1 0 1 empty empty up-coeff 5 7 1 11 -257472 -1 -1 1335 0; #X obj 120 225 hsl 90 15 -1 1 0 0 empty empty left-coeff 5 7 1 11 -257472 --1 -1 8900 0; +-1 -1 0 0; #X obj 103 170 hsl 90 15 -1 1 0 1 empty empty right-coeff 5 7 1 10 -257472 -1 -1 8900 0; #X msg 220 203 up-coeff \$1; @@ -83,18 +83,18 @@ the parameters for each direction.; #X obj 100 187 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 1 256; #X obj 117 242 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 --233017 -1 -1 1 256; +-233017 -1 -1 0 256; #X obj 226 242 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 -1 256; #X obj 220 187 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 -0.7 256; -#X obj 242 301 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +#X obj 279 301 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 1204.41 256; -#X obj 245 357 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +#X obj 282 357 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 301.102 256; -#X obj 255 413 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +#X obj 292 413 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 0 256; -#X obj 260 467 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 +#X obj 297 467 nbx 6 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 1 10 -233017 -1 -1 19996.7 256; #X obj 3 3 cnv 15 850 30 empty empty [ff-spring] 15 15 1 18 -257472 -1 0; @@ -107,6 +107,9 @@ the parameters for each direction.; #X floatatom 195 624 5 0 0 0 - - -; #X text 397 58 [ff-spring] is a "conditional effect".; #X text 396 110 [ff-friction] has the same methods; +#X msg 36 387 load; +#X msg 73 387 unload; +#X text 9 369 load/unload effect; #X connect 12 0 32 0; #X connect 13 0 33 0; #X connect 14 0 34 0; @@ -152,3 +155,5 @@ the parameters for each direction.; #X connect 59 0 21 0; #X connect 60 0 17 0; #X connect 61 0 16 0; +#X connect 70 0 39 0; +#X connect 71 0 39 0; -- cgit v1.2.1 From 35a3b5acb916a03d8d1821b8e370a5cc3615a2b9 Mon Sep 17 00:00:00 2001 From: Gerard van Dongen Date: Sat, 29 May 2004 08:04:56 +0000 Subject: fixed typo in conditional expression svn path=/trunk/externals/ff/; revision=1786 --- ff/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/ff.c b/ff/ff.c index 20cbc4d..64a10d1 100644 --- a/ff/ff.c +++ b/ff/ff.c @@ -149,7 +149,7 @@ void ff_stop(t_ff *x) perror("couldn't read status of effect"); } - if (x->do_that.value = FF_STATUS_PLAYING) { + if (x->do_that.value == FF_STATUS_PLAYING) { x->do_that.type = EV_FF; x->do_that.code = x->effects.id; -- cgit v1.2.1 From 167c1dc71bac9d7e9d05918fd80f9cf557f53400 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 26 Apr 2005 04:13:39 +0000 Subject: added pddp_open patch to open all_about_ patches without them being abstractions embedded in the help files svn path=/trunk/externals/ff/; revision=2818 --- ff/ff-autocenter-help.pd | 2 +- ff/ff-constant-help.pd | 2 +- ff/ff-friction-help.pd | 2 +- ff/ff-gain-help.pd | 2 +- ff/ff-periodic-help.pd | 2 +- ff/ff-spring-help.pd | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ff/ff-autocenter-help.pd b/ff/ff-autocenter-help.pd index 91e9f7e..e5ba559 100644 --- a/ff/ff-autocenter-help.pd +++ b/ff/ff-autocenter-help.pd @@ -11,7 +11,7 @@ controlled used [ff-gain].; #X text 19 102 creation arguments are device number (i.e. 0 for /dev/input/event0) and autocenter amount. This effects all effects for that device; #X obj 77 277 ff-autocenter 0 0; -#X obj 303 323 all_about_haptics; +#X obj 303 323 pddp_open all_about_haptics; #X text 190 325 For more info:; #X msg 77 197 0.5; #X connect 1 0 6 0; diff --git a/ff/ff-constant-help.pd b/ff/ff-constant-help.pd index 411ebb5..5bd0c75 100644 --- a/ff/ff-constant-help.pd +++ b/ff/ff-constant-help.pd @@ -62,7 +62,7 @@ -1 -1; #X obj 3 3 cnv 15 850 30 empty empty [ff-constant] 15 15 1 18 -262131 -1 0; -#X obj 642 111 all_about_haptics; +#X obj 642 111 pddp_open all_about_haptics; #X text 530 110 For more info:; #X text 394 556 <-- arguments are: device# direction duration level ; diff --git a/ff/ff-friction-help.pd b/ff/ff-friction-help.pd index e169d2d..970b9e4 100644 --- a/ff/ff-friction-help.pd +++ b/ff/ff-friction-help.pd @@ -98,7 +98,7 @@ the parameters for each direction.; -233017 -1 -1 19996.7 256; #X obj 3 3 cnv 15 850 30 empty empty [ff-friction] 15 15 1 18 -257472 -1 0; -#X obj 568 135 all_about_haptics; +#X obj 568 135 pddp_open all_about_haptics; #X text 456 134 For more info:; #X text 428 599 arguments are: device# duration right- left- up- down-level ; diff --git a/ff/ff-gain-help.pd b/ff/ff-gain-help.pd index e82e005..e665ec2 100644 --- a/ff/ff-gain-help.pd +++ b/ff/ff-gain-help.pd @@ -5,7 +5,7 @@ #X obj 3 3 cnv 15 450 30 empty empty [ff-gain] 4 12 1 18 -261689 -1 0; #X obj 123 254 ff-gain 0 0.5; -#X obj 320 326 all_about_haptics; +#X obj 320 326 pddp_open all_about_haptics; #X text 214 326 For more info:; #X msg 123 178 0.9; #X text 24 102 Creation arguments are device number (i.e. 0 for /dev/input/event0) diff --git a/ff/ff-periodic-help.pd b/ff/ff-periodic-help.pd index a518aea..4138369 100644 --- a/ff/ff-periodic-help.pd +++ b/ff/ff-periodic-help.pd @@ -92,7 +92,7 @@ -1 if it is not loaded.; #X floatatom 319 603 5 0 0 0 - - -; #X text 554 107 For more info:; -#X obj 663 106 all_about_haptics; +#X obj 663 106 pddp_open all_about_haptics; #X text 300 335 minimum time; #X text 300 350 between triggers; #X text 422 56 [ff-periodic] generates a periodic force \, basically diff --git a/ff/ff-spring-help.pd b/ff/ff-spring-help.pd index c5eaa9a..05888e1 100644 --- a/ff/ff-spring-help.pd +++ b/ff/ff-spring-help.pd @@ -98,7 +98,7 @@ the parameters for each direction.; -233017 -1 -1 19996.7 256; #X obj 3 3 cnv 15 850 30 empty empty [ff-spring] 15 15 1 18 -257472 -1 0; -#X obj 568 135 all_about_haptics; +#X obj 568 135 pddp_open all_about_haptics; #X text 456 134 For more info:; #X text 415 599 arguments are: device# duration right- left- up- down-level ; -- cgit v1.2.1 From ab458c04316de82723f41e7f22f4b282637612bb Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 17 Jan 2006 05:03:12 +0000 Subject: changed the slider to a toggle to reflect the actual control you have over autocentering svn path=/trunk/externals/ff/; revision=4429 --- ff/ff-autocenter-help.pd | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/ff/ff-autocenter-help.pd b/ff/ff-autocenter-help.pd index e5ba559..4338ff6 100644 --- a/ff/ff-autocenter-help.pd +++ b/ff/ff-autocenter-help.pd @@ -1,9 +1,7 @@ -#N canvas 205 279 460 360 10; +#N canvas 120 116 464 364 10; #X text 20 66 sets the amount of "autocentering" of the force-feedback joystick. Range is [0 \, 1]. 0 is no auto-centering; #X floatatom 77 254 5 0 0 0 - - -; -#X obj 80 226 hsl 225 17 0 1 0 0 empty empty auto-center 25 9 1 12 --261689 -1 -1 0 0; #X text 19 149 This is affected by the overall gain \, which can be controlled used [ff-gain].; #X obj 4 4 cnv 15 450 30 empty empty [ff-autocenter] 4 12 1 18 -261689 @@ -11,9 +9,9 @@ controlled used [ff-gain].; #X text 19 102 creation arguments are device number (i.e. 0 for /dev/input/event0) and autocenter amount. This effects all effects for that device; #X obj 77 277 ff-autocenter 0 0; -#X obj 303 323 pddp_open all_about_haptics; -#X text 190 325 For more info:; -#X msg 77 197 0.5; -#X connect 1 0 6 0; -#X connect 2 0 1 0; -#X connect 9 0 2 0; +#X obj 253 323 pddp_open all_about_haptics; +#X text 140 325 For more info:; +#X obj 77 211 tgl 30 0 empty empty start 1 15 1 12 -90049 -1 -1 0 1 +; +#X connect 1 0 5 0; +#X connect 8 0 1 0; -- cgit v1.2.1 From 03ed882eb5f31d961857c8c72d33a8879e7dff2e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 9 Jun 2009 17:34:48 +0000 Subject: replaced -export_dynamic with --export-dynamic and -Wl,--export-dynamic where appropriate. It seems that once upon a time -export_dynamic was a real flag. Now it means -e xport_dynamic, meaning set the entry symbol to xport_dynamic, giving this error message: /usr/bin/ld: warning: cannot find entry symbol xport_dynamic; defaulting to 0000000000001b60 svn path=/trunk/externals/ff/; revision=11724 --- ff/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/makefile b/ff/makefile index 7708283..0ed84d5 100644 --- a/ff/makefile +++ b/ff/makefile @@ -5,7 +5,7 @@ all: ff ff: ff.c $(CC) $(CFLAGS) $(LINUXCFLAGS) $(LINUXINCLUDE) -o ff.o -c ff.c - ld -export_dynamic -shared -o ff.pd_linux ff.o -lc -lm + ld --export-dynamic -shared -o ff.pd_linux ff.o -lc -lm strip --strip-unneeded ff.pd_linux rm ff.o -- cgit v1.2.1 From 86c89e24f57b63883775f932c0a2354b5fe4660c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 11:36:22 +0000 Subject: dmx4pd (currently linux only) svn path=/trunk/externals/iem/dmx512/; revision=9989 --- dmx512/GnuGPL.txt | 340 ++++++++++++++++++++++++++++++++++++++++++++++ dmx512/README.txt | 4 + dmx512/src/Make.config.in | 31 +++++ dmx512/src/Make.version | 1 + dmx512/src/Makefile | 64 +++++++++ dmx512/src/configure.ac | 181 ++++++++++++++++++++++++ dmx512/src/dmx4pd.h | 34 +++++ dmx512/src/dmxin.c | 47 +++++++ dmx512/src/dmxout.c | 156 +++++++++++++++++++++ 9 files changed, 858 insertions(+) create mode 100644 dmx512/GnuGPL.txt create mode 100644 dmx512/README.txt create mode 100644 dmx512/src/Make.config.in create mode 100644 dmx512/src/Make.version create mode 100644 dmx512/src/Makefile create mode 100644 dmx512/src/configure.ac create mode 100644 dmx512/src/dmx4pd.h create mode 100644 dmx512/src/dmxin.c create mode 100644 dmx512/src/dmxout.c diff --git a/dmx512/GnuGPL.txt b/dmx512/GnuGPL.txt new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/dmx512/GnuGPL.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/dmx512/README.txt b/dmx512/README.txt new file mode 100644 index 0000000..96579bc --- /dev/null +++ b/dmx512/README.txt @@ -0,0 +1,4 @@ +DMX512 +====== + +controlling DMX from within Pd diff --git a/dmx512/src/Make.config.in b/dmx512/src/Make.config.in new file mode 100644 index 0000000..d3ac25f --- /dev/null +++ b/dmx512/src/Make.config.in @@ -0,0 +1,31 @@ +LIBNAME ?= @LIBNAME@ +VERSION ?= @VERSION@ + +PREFIX =@prefix@@PDLIBDIR@ + +INSTALL_BIN=$(PREFIX)/extra +INSTALL_DOC=$(PREFIX)/@REFERENCEPATH@$(LIBNAME) + +EXT = @EXT@ +VERSION ?= @VERSION@ +DEFS = @DFLAGS@ -DACONNECT_VERSION=\"$(VERSION)\" +IFLAGS = -I. @INCLUDES@ $(INCLUDES) + +CC = @CC@ +LD = @LD@ +STRIP = @STRIP@ @STRIPFLAGS@ + +AFLAGS = +LFLAGS = @LFLAGS@ +WFLAGS = + +MAKEDEP_FLAGS = @MAKEDEP_FLAGS@ + +TARNAME = $(LIBNAME)-$(VERSION).tgz +BINTARNAME = $(LIBNAME)-$(VERSION)-bin.tgz + + +CFLAGS = $(DEFS) $(IFLAGS) $(WFLAGS) @CFLAGS@ + +LIBS = @LIBS@ + diff --git a/dmx512/src/Make.version b/dmx512/src/Make.version new file mode 100644 index 0000000..0bc041a --- /dev/null +++ b/dmx512/src/Make.version @@ -0,0 +1 @@ +VERSION = $(shell svnversion) diff --git a/dmx512/src/Makefile b/dmx512/src/Makefile new file mode 100644 index 0000000..93da650 --- /dev/null +++ b/dmx512/src/Makefile @@ -0,0 +1,64 @@ +default: all + +include Make.version + +Make.config: Make.config.in configure + ./configure + +include Make.config + +.SUFFIXES: .$(EXT) + +SOURCES=$(sort $(filter %.c, $(wildcard *.c))) +TARGETS = $(SOURCES:.c=.o) +OBJECTS = $(SOURCES:.c=.$(EXT)) + +all: $(OBJECTS) + +clean: + -rm -f *.o *.d + +binclean: + -rm -f *.$(EXT) + +distclean: clean binclean + -rm -f *~ _* config.* + -rm -rf autom4te.cache + +install: install-bin install-doc + +install-bin: + -install -d $(INSTALL_BIN) + -install -m 644 $(LIBNAME).$(EXT) $(INSTALL_BIN) + +install-doc: + -install -d $(INSTALL_BIN) + -install -m 644 *.pd $(INSTALL_BIN) + +dist: distclean + (cd ..;tar czvf $(TARNAME) $(LIBNAME)) + +distbin: distclean all clean + (cd ..; tar cvzf $(BINTARNAME) $(LIBNAME)) + +everything: clean all install distclean + + +$(TARGETS): %.o : %.c + $(CC) $(DMX4PD_CFLAGS) -DDMX4PD_VERSION="\"$(VERSION)\"" -c -o $@ $*.c + +$(OBJECTS): %.$(EXT) : %.o + $(LD) $(LFLAGS) -o $@ $*.o $(LIBS) + $(STRIP) $(STRIPFLAGS) $@ + +## dependencies: as proposed by the GNU-make documentation +## see http://www.gnu.org/software/make/manual/html_node/make_47.html#SEC51 +-include $(SOURCES:.c=.d) +%.d: %.c + @set -e; rm -f $@; \ + $(CC) $(MAKEDEP_FLAGS) $(CFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +configure: configure.ac + autoconf diff --git a/dmx512/src/configure.ac b/dmx512/src/configure.ac new file mode 100644 index 0000000..ce4dc98 --- /dev/null +++ b/dmx512/src/configure.ac @@ -0,0 +1,181 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(dmx4pd.h) + +LIBNAME=dmx4pd + +dnl Checks for programs. +AC_PROG_CC + +AC_SUBST(STK) +AC_SUBST(DFLAGS) +AC_SUBST(LFLAGS) +AC_SUBST(EXT) +AC_SUBST(LD) +AC_SUBST(STRIP) +AC_SUBST(STRIPFLAGS) +AC_SUBST(REFERENCEPATH) +AC_SUBST(PDLIBDIR) +AC_SUBST(INCLUDES) +AC_SUBST(LIBNAME) + +AC_SUBST(DMX4LINUX_LFLAGS) +AC_SUBST(DMX4LINUX_CFLAGS) + + +AC_ARG_WITH(pdversion, [ --with-pdversion= enforce a certain pd-version (e.g. 0.37)]) +AC_ARG_WITH(extension, [ --with-extension= enforce a certain extension for the dynamic library (e.g. dll)]) + + +dnl Checks for libraries. +dnl Replace `main' with a function in -lc: +AC_CHECK_LIB(c, main) +AC_CHECK_LIB(crtdll, fclose) + +dnl Replace `main' with a function in -lm: +AC_CHECK_LIB(m, main) +dnl Replace `main' with a function in -lpthread: +dnl AC_CHECK_LIB(pthread, main) +dnl Replace `main' with a function in -lstk: +dnl AC_CHECK_LIB(stk, main, STK=yes) + + +AC_CHECK_LIB(dmx4linux, DMXsleep) +if test "x$ac_cv_lib_dmx4linux_DMXsleep" = "xyes"; then + DMX4LINUX_LFLAGS="-ldmx4linux" +fi + +dnl AC_CHECK_LIB(asound, snd_seq_close) +dnl if test "x$ac_cv_lib_asound_snd_seq_close" = "xyes"; then +dnl DFLAGS="-DHAVE_ALSA ${DFLAGS}" +dnl fi + +if test "x$includedir" != "x"; then + for id in $includedir + do + if test -d $id; then INCLUDES="-I$id $INCLUDES"; fi + done +fi +if test "x$libdir" != "x"; then + for id in $libdir + do + if test -d $id; then LIBS="-L$id $LIBS"; fi + done +fi + +AC_CHECK_LIB(pd, nullfn) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(stdlib.h stdio.h string.h math.h time.h sys/time.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_TIME + +dnl Checks for library functions. +AC_FUNC_MMAP +AC_CHECK_FUNCS(select socket strerror) + +dnl check for "-mms-bitfields" cflag +dnl why is there no generic compiler-check for a given flag ? +dnl it would make things so easy: AC_CHECK_FLAG([-mms-bitfields],,) +AC_MSG_CHECKING("ms-bitfields") +cat > conftest.c << EOF +int main(){ + return 0; +} +EOF +if ${CC} ${INCLUDES} ${DFLAGS} -o conftest.o conftest.c ${CFLAGS} -mms-bitfields > /dev/null 2>&1 +then + echo "yes" + CFLAGS="${CFLAGS} -mms-bitfields" +else + echo "no" +fi + + +### make-depend flags +if test "x$ac_cv_c_compiler_gnu" = "xyes"; then + AC_SUBST(MAKEDEP_FLAGS, "-MM") +else + AC_SUBST(MAKEDEP_FLAGS, "-M") +fi + +dnl isn't there a better way to check for good linker/stripper ? + +dnl if we don't have $LD set, we set it to $(CC) +dnl LD=${LD:=$CC} +AC_CHECK_TOOL([LD], [ld], [${CC}]) + +dnl if we don't have $STRIP set, we set it to ${host}-strip or strip + +dnl if we don't have $STRIP set, we set it to ${host}-strip or strip +AC_CHECK_TOOL([STRIP], [strip], [true]) +AC_MSG_CHECKING([if strip is GNU strip]) +if $STRIP -V | grep GNU > /dev/null +then + AC_SUBST(STRIPFLAGS, "--strip-unneeded") + AC_MSG_RESULT([yes]) +else + AC_SUBST(STRIPFLAGS,"-x") + AC_MSG_RESULT([no]) +fi + +dnl +dnl OK, checks for machines are here now +dnl +if test `uname -s` = Linux; +then + LFLAGS="-export_dynamic -shared" + CFLAGS="-fPIC $CFLAGS" + EXT=pd_linux +fi + +dnl This should use '-bundle_loader /path/to/pd/bin/pd' instead of'-undefined suppress' +dnl then strip might do something +if test `uname -s` = Darwin; +then + LD=cc + LFLAGS="-bundle -undefined suppress -flat_namespace" + EXT=pd_darwin + STRIPFLAGS= +fi + +if test `uname | sed -e 's/^MINGW.*/NT/'` = NT; +then + LD=gcc + INCLUDES="-I@prefix@/src" + DFLAGS="-D__WIN32__ ${DFLAGS}" + LFLAGS="-shared @prefix@/bin/pd.dll" + EXT=dll +else + PDLIBDIR="/lib/pd" +fi + +if test `uname -s` = IRIX64; +then + LFLAGS="-n32 -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \ + -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \ + -shared -rdata_shared" + EXT=pd_irix6 + dnl DFLAGS="-DUNIX -DIRIX6 ${DFLAGS}" + STRIPFLAGS="--strip-unneeded" +fi + +if test `uname -s` = IRIX32; +then + LFLAGS="-o32 -DUNIX -DIRIX -O2 + -shared -rdata_shared" + EXT=pd_irix5 + dnl DFLAGS="-DUNIX -DIRIX5 ${DFLAGS}" + STRIPFLAGS="--strip-unneeded" +fi + +if test "x$with_extension" != "x" +then + EXT=$with_extension +fi + + +AC_OUTPUT(Make.config) + +rm -f conftest.* diff --git a/dmx512/src/dmx4pd.h b/dmx512/src/dmx4pd.h new file mode 100644 index 0000000..0987926 --- /dev/null +++ b/dmx512/src/dmx4pd.h @@ -0,0 +1,34 @@ + +/****************************************************** + * + * dmx4pd - header file + * + * copyleft (c) IOhannes m zm-bölnig-A + * + * 0603:forum::f-bür::umläute:2008-A + * + * institute of electronic music and acoustics (iem) + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#ifndef INCLUDE_DMX4PD_H__ +#define INCLUDE_DMX4PD_H__ + +#ifndef DMX4PD_VERSION +# define DMX4PD_VERSION __DATE__ +#endif + + + +#include "m_pd.h" + +#define DMX4PD_POSTBANNER \ + post("DMX4PD ver %s: (c) 2008 IOhannes m zmölnig - iem @ kug", DMX4PD_VERSION); + + + +#endif /* INCLUDE_DMX4PD_H__ */ diff --git a/dmx512/src/dmxin.c b/dmx512/src/dmxin.c new file mode 100644 index 0000000..9e9e1b4 --- /dev/null +++ b/dmx512/src/dmxin.c @@ -0,0 +1,47 @@ +/****************************************************** + * + * dmxin - implementation file + * + * copyleft (c) IOhannes m zmölnig + * + * 0603:forum::für::umläute:2008 + * + * institute of electronic music and acoustics (iem) + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + + +#include "dmx4pd.h" + +static t_class *dmxin_class; + +typedef struct _dmxin +{ + t_object x_obj; +} t_dmxin; + +static void *dmxin_new(void) +{ + t_dmxin *x = (t_dmxin *)pd_new(dmxin_class); + return (x); +} +static void *dmxin_free(t_dmxin*x) +{ + +} + +void dmxin_setup(void) +{ + dmxin_class = class_new(gensym("dmxin"), (t_newmethod)dmxin_new, (t_method)dmxin_free, + sizeof(t_dmxin), + CLASS_NOINLET, + A_NULL); + +#ifdef DMX4PD_POSTBANNER + DMX4PD_POSTBANNER +#endif +} diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c new file mode 100644 index 0000000..5fa17ba --- /dev/null +++ b/dmx512/src/dmxout.c @@ -0,0 +1,156 @@ +/****************************************************** + * + * dmxout - implementation file + * + * copyleft (c) IOhannes m zmölnig + * + * 0603:forum::für::umläute:2008 + * + * institute of electronic music and acoustics (iem) + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + + +#include "dmx4pd.h" + +#include +#include +#include +#include + + +#include + +static t_class *dmxout_class; + +typedef struct _dmxout +{ + t_object x_obj; + + t_inlet *x_portinlet; + + int x_device; + t_float x_port; + +} t_dmxout; + + +static void dmxout_doout(t_dmxout*x, short port, unsigned char value) +{ + dmx_t buffer[1] = {value}; + if(x->x_device<=0) { + pd_error(x, "no DMX universe found"); + return; + } + + lseek (x->x_device, sizeof(buffer)*port, SEEK_SET); /* set to the current channel */ + write (x->x_device, buffer, sizeof(buffer)); /* write the channel */ +} + + +static void dmxout_close(t_dmxout*x) +{ + if(x->x_device>=0) { + close(x->x_device); + } + x->x_device=-1; +} + + +static void dmxout_open(t_dmxout*x, t_symbol*s_devname) +{ + int argc=2; + char *args[2] = {"--dmx", s_devname->s_name}; + const char**argv=args; + char*devname=""; + int fd; + + if(s_devname && s_devname->s_name) + devname=s_devname->s_name; + + // strncpy(args[0], "--dmx", MAXPDSTRING); + // strncpy(args[1], devname, MAXPDSTRING); + + fd = open (DMXdev(&argc, argv), O_WRONLY); + + if(fd!=-1) { + dmxout_close(x); + x->x_device=fd; + } +} + + +static void dmxout_float(t_dmxout*x, t_float f) +{ + unsigned char val=(unsigned char)f; + short port = (short)x->x_port; + if(f<0. || f>255.) { + pd_error(x, "value %f out of bounds [0..255]", f); + return; + } + if(x->x_port<0. || x->x_port>512.) { + pd_error(x, "port %f out of bounds [0..512]", x->x_port); + return; + } + + dmxout_doout(x, port, val); +} + +static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) +{ + t_dmxout *x = (t_dmxout *)pd_new(dmxout_class); + + t_symbol*devname=gensym(""); + + x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); + + x->x_device=-1; + x->x_port =0; + + switch(argc) { + case 0: break; + case 1: + if(A_FLOAT==argv->a_type) { + x->x_port=atom_getfloat(argv); + } else { + devname=atom_getsymbol(argv); + } + break; + default: + if((A_FLOAT==(argv+0)->a_type) && (A_SYMBOL==(argv+1)->a_type)) { + x->x_port=atom_getfloat(argv+0); + devname=atom_getsymbol(argv+1); + } else if(A_FLOAT==(argv+1)->a_type && A_SYMBOL==(argv+0)->a_type) { + x->x_port=atom_getfloat(argv+1); + devname=atom_getsymbol (argv+0); + } + break; + } + + + dmxout_open(x, devname); + return (x); +} + +static void *dmxout_free(t_dmxout*x) +{ + +} + + +void dmxout_setup(void) +{ + dmxout_class = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, + sizeof(t_dmxout), + 0, + A_GIMME, A_NULL); + + class_addfloat(dmxout_class, dmxout_float); + + + post("DMX4PD (%s): (c) 2008 IOhannes m zmölnig - iem @ kug", DMX4PD_VERSION); +} -- cgit v1.2.1 From cea4322c3ca725ebc4096740b6060b02064a4a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 12:44:31 +0000 Subject: trying to fix makefile svn path=/trunk/externals/iem/dmx512/; revision=9990 --- dmx512/src/Makefile | 14 ++++++++++---- dmx512/src/dmxout.c | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dmx512/src/Makefile b/dmx512/src/Makefile index 93da650..c751028 100644 --- a/dmx512/src/Makefile +++ b/dmx512/src/Makefile @@ -5,7 +5,7 @@ include Make.version Make.config: Make.config.in configure ./configure -include Make.config +-include Make.config .SUFFIXES: .$(EXT) @@ -16,10 +16,13 @@ OBJECTS = $(SOURCES:.c=.$(EXT)) all: $(OBJECTS) clean: - -rm -f *.o *.d + -rm -f *.o *.d binclean: - -rm -f *.$(EXT) + -rm -f *.$(EXT) *.dll *.pd_linux *.pd_darwin *.l_i386 *.l_ia64 *.d_ppc *.d_fat + +mrproper: distclean + -rm Make.config configure *.d.* distclean: clean binclean -rm -f *~ _* config.* @@ -44,13 +47,15 @@ distbin: distclean all clean everything: clean all install distclean -$(TARGETS): %.o : %.c +$(TARGETS): %.o : %.c Make.config $(CC) $(DMX4PD_CFLAGS) -DDMX4PD_VERSION="\"$(VERSION)\"" -c -o $@ $*.c $(OBJECTS): %.$(EXT) : %.o $(LD) $(LFLAGS) -o $@ $*.o $(LIBS) $(STRIP) $(STRIPFLAGS) $@ + +ifeq (,$(findstring clean, $(MAKECMDGOALS))) ## dependencies: as proposed by the GNU-make documentation ## see http://www.gnu.org/software/make/manual/html_node/make_47.html#SEC51 -include $(SOURCES:.c=.d) @@ -62,3 +67,4 @@ $(OBJECTS): %.$(EXT) : %.o configure: configure.ac autoconf +endif diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index 5fa17ba..af812b9 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -152,5 +152,5 @@ void dmxout_setup(void) class_addfloat(dmxout_class, dmxout_float); - post("DMX4PD (%s): (c) 2008 IOhannes m zmölnig - iem @ kug", DMX4PD_VERSION); + post("DMX4PD (ver.%s): (c) 2008 IOhannes m zmölnig - iem @ kug", DMX4PD_VERSION); } -- cgit v1.2.1 From 4fd2d8a51cea2577f985148583539d0f7727da63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 12:46:17 +0000 Subject: this should do svn path=/trunk/externals/iem/dmx512/; revision=9991 --- dmx512/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmx512/src/Makefile b/dmx512/src/Makefile index c751028..a9c06db 100644 --- a/dmx512/src/Makefile +++ b/dmx512/src/Makefile @@ -18,7 +18,7 @@ all: $(OBJECTS) clean: -rm -f *.o *.d -binclean: +binclean: clean -rm -f *.$(EXT) *.dll *.pd_linux *.pd_darwin *.l_i386 *.l_ia64 *.d_ppc *.d_fat mrproper: distclean -- cgit v1.2.1 From 124ec02a0b4114bb52bcb8c44c4d76de737f6e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 13:28:08 +0000 Subject: probably got the svnversion magic going svn path=/trunk/externals/iem/dmx512/; revision=9992 --- dmx512/src/Make.version | 2 +- dmx512/src/Makefile | 8 +++++++- dmx512/src/dmx4pd.h | 6 ++++-- dmx512/src/dmxout.c | 9 +++++---- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/dmx512/src/Make.version b/dmx512/src/Make.version index 0bc041a..0bdb8b4 100644 --- a/dmx512/src/Make.version +++ b/dmx512/src/Make.version @@ -1 +1 @@ -VERSION = $(shell svnversion) +VERSION = $(shell svnversion | grep -e "[0-9]") diff --git a/dmx512/src/Makefile b/dmx512/src/Makefile index a9c06db..e634df6 100644 --- a/dmx512/src/Makefile +++ b/dmx512/src/Makefile @@ -2,11 +2,17 @@ default: all include Make.version + Make.config: Make.config.in configure ./configure -include Make.config +#VERSIONDEFINE = _$(strip $(VERSION))_ +ifneq ($(strip $(VERSION)),) +VERSIONDEFINE = -DDMX4PD_VERSION="\"rev.$(VERSION)\"" +endif + .SUFFIXES: .$(EXT) SOURCES=$(sort $(filter %.c, $(wildcard *.c))) @@ -48,7 +54,7 @@ everything: clean all install distclean $(TARGETS): %.o : %.c Make.config - $(CC) $(DMX4PD_CFLAGS) -DDMX4PD_VERSION="\"$(VERSION)\"" -c -o $@ $*.c + $(CC) $(DMX4PD_CFLAGS) $(VERSIONDEFINE) -c -o $@ $*.c $(OBJECTS): %.$(EXT) : %.o $(LD) $(LFLAGS) -o $@ $*.o $(LIBS) diff --git a/dmx512/src/dmx4pd.h b/dmx512/src/dmx4pd.h index 0987926..d386c28 100644 --- a/dmx512/src/dmx4pd.h +++ b/dmx512/src/dmx4pd.h @@ -26,9 +26,11 @@ #include "m_pd.h" -#define DMX4PD_POSTBANNER \ - post("DMX4PD ver %s: (c) 2008 IOhannes m zmölnig - iem @ kug", DMX4PD_VERSION); +#define DMX4PD_POSTBANNER \ + { \ + post("DMX4PD ("DMX4PD_VERSION"): (c) 2008 IOhannes m zmölnig - iem @ kug"); \ + } #endif /* INCLUDE_DMX4PD_H__ */ diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index af812b9..b9066cb 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -64,7 +64,7 @@ static void dmxout_close(t_dmxout*x) static void dmxout_open(t_dmxout*x, t_symbol*s_devname) { int argc=2; - char *args[2] = {"--dmx", s_devname->s_name}; + const char *args[2] = {"--dmx", s_devname->s_name}; const char**argv=args; char*devname=""; int fd; @@ -138,7 +138,7 @@ static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) static void *dmxout_free(t_dmxout*x) { - + dmxout_close(x); } @@ -151,6 +151,7 @@ void dmxout_setup(void) class_addfloat(dmxout_class, dmxout_float); - - post("DMX4PD (ver.%s): (c) 2008 IOhannes m zmölnig - iem @ kug", DMX4PD_VERSION); +#ifdef DMX4PD_POSTBANNER + DMX4PD_POSTBANNER +#endif } -- cgit v1.2.1 From 44824cfa333691b8e300adbc47bcadcde6691979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 13:39:54 +0000 Subject: tell that [dmxin] isn't yet there... svn path=/trunk/externals/iem/dmx512/; revision=9993 --- dmx512/src/dmx4pd.h | 5 +++++ dmx512/src/dmxin.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- dmx512/src/dmxout.c | 5 ----- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/dmx512/src/dmx4pd.h b/dmx512/src/dmx4pd.h index d386c28..cc6fe66 100644 --- a/dmx512/src/dmx4pd.h +++ b/dmx512/src/dmx4pd.h @@ -25,6 +25,11 @@ #include "m_pd.h" +#include + +#include +#include +#include #define DMX4PD_POSTBANNER \ diff --git a/dmx512/src/dmxin.c b/dmx512/src/dmxin.c index 9e9e1b4..cfccd4b 100644 --- a/dmx512/src/dmxin.c +++ b/dmx512/src/dmxin.c @@ -17,21 +17,65 @@ #include "dmx4pd.h" + static t_class *dmxin_class; typedef struct _dmxin { t_object x_obj; + int x_device; + + t_outlet*x_outlet1, *x_outlet2; } t_dmxin; + + + +static void dmxin_close(t_dmxin*x) +{ + if(x->x_device>=0) { + close(x->x_device); + } + x->x_device=-1; +} + + +static void dmxin_open(t_dmxin*x, t_symbol*s_devname) +{ + int argc=2; + const char *args[2] = {"--dmx", s_devname->s_name}; + const char**argv=args; + char*devname=""; + int fd; + + if(s_devname && s_devname->s_name) + devname=s_devname->s_name; + + // strncpy(args[0], "--dmx", MAXPDSTRING); + // strncpy(args[1], devname, MAXPDSTRING); + + fd = open (DMXINdev(&argc, argv), O_RDONLY); + + if(fd!=-1) { + dmxin_close(x); + x->x_device=fd; + } +} + + static void *dmxin_new(void) { - t_dmxin *x = (t_dmxin *)pd_new(dmxin_class); - return (x); + if(0) { + t_dmxin *x = (t_dmxin *)pd_new(dmxin_class); + return (x); + } else { + error("[dmxin] not yet implemented"); + return 0; + } } static void *dmxin_free(t_dmxin*x) { - + dmxin_close(x); } void dmxin_setup(void) diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index b9066cb..fc3a875 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -17,14 +17,9 @@ #include "dmx4pd.h" -#include -#include #include #include - -#include - static t_class *dmxout_class; typedef struct _dmxout -- cgit v1.2.1 From d63eaa6f1814f289c52cecaa4c7d76e765269549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 13:42:01 +0000 Subject: ... svn path=/trunk/externals/iem/dmx512/; revision=9994 --- dmx512/src/dmxout.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index fc3a875..08d70b2 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -33,20 +33,6 @@ typedef struct _dmxout } t_dmxout; - -static void dmxout_doout(t_dmxout*x, short port, unsigned char value) -{ - dmx_t buffer[1] = {value}; - if(x->x_device<=0) { - pd_error(x, "no DMX universe found"); - return; - } - - lseek (x->x_device, sizeof(buffer)*port, SEEK_SET); /* set to the current channel */ - write (x->x_device, buffer, sizeof(buffer)); /* write the channel */ -} - - static void dmxout_close(t_dmxout*x) { if(x->x_device>=0) { @@ -78,6 +64,18 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) } } +static void dmxout_doout(t_dmxout*x, short port, unsigned char value) +{ + dmx_t buffer[1] = {value}; + if(x->x_device<=0) { + pd_error(x, "no DMX universe found"); + return; + } + + lseek (x->x_device, sizeof(buffer)*port, SEEK_SET); /* set to the current channel */ + write (x->x_device, buffer, sizeof(buffer)); /* write the channel */ +} + static void dmxout_float(t_dmxout*x, t_float f) { -- cgit v1.2.1 From a1130c53ea736d68d8d2a260d80a7e182a638813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 13 Jun 2008 14:36:24 +0000 Subject: ... svn path=/trunk/externals/iem/dmx512/; revision=9997 --- dmx512/src/dmxin.c | 74 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/dmx512/src/dmxin.c b/dmx512/src/dmxin.c index cfccd4b..c009570 100644 --- a/dmx512/src/dmxin.c +++ b/dmx512/src/dmxin.c @@ -17,6 +17,10 @@ #include "dmx4pd.h" +#include +#include +#include +#include static t_class *dmxin_class; @@ -24,12 +28,43 @@ typedef struct _dmxin { t_object x_obj; int x_device; + int x_port; - t_outlet*x_outlet1, *x_outlet2; -} t_dmxin; + dmx_t x_dmxbuffer[512]; + t_outlet*x_outlet1, *x_outlet2; +} t_dmxin; +static void dmx_doread(t_dmxin*x) { + int dmxin=x->x_device; + fd_set readset; + post("dmxin_doread: %d", dmxin); + if(dmxin<=0)return; + + FD_ZERO(&readset); + FD_SET(dmxin, &readset); + FD_SET(0, &readset); + + int n=select(dmxin+1, &readset, NULL,NULL, NULL); + if(n>0 && FD_ISSET(dmxin, &readset)) { + dmx_t dmxbuffer[512]; + int i=0; + lseek (dmxin, 0, SEEK_SET); + n=read (dmxin, dmxbuffer, sizeof(dmxbuffer)); + for(i=0; i<512; i+=2) { + int c=dmxbuffer[i]; + if(c!=x->x_dmxbuffer[i]) { + x->x_dmxbuffer[i]=c; + post("read %03d @ %03d", c, i); + } + } + } +} +static void dmxin_bang(t_dmxin*x) +{ + dmx_doread(x); +} static void dmxin_close(t_dmxin*x) { @@ -43,7 +78,7 @@ static void dmxin_close(t_dmxin*x) static void dmxin_open(t_dmxin*x, t_symbol*s_devname) { int argc=2; - const char *args[2] = {"--dmx", s_devname->s_name}; + const char *args[2] = {"--dmxin", s_devname->s_name}; const char**argv=args; char*devname=""; int fd; @@ -65,15 +100,26 @@ static void dmxin_open(t_dmxin*x, t_symbol*s_devname) static void *dmxin_new(void) { - if(0) { - t_dmxin *x = (t_dmxin *)pd_new(dmxin_class); - return (x); - } else { - error("[dmxin] not yet implemented"); - return 0; + int i=0; + t_dmxin *x = (t_dmxin *)pd_new(dmxin_class); + + x->x_device=0; + x->x_port=0; + + for(i=0; ix_dmxbuffer); i++) { + x->x_dmxbuffer[i]=0; } + + + x->x_outlet1=outlet_new(&x->x_obj, &s_float); + x->x_outlet2=outlet_new(&x->x_obj, &s_float); + + + + dmxin_open(x, gensym("")); + return (x); } -static void *dmxin_free(t_dmxin*x) +static void dmxin_free(t_dmxin*x) { dmxin_close(x); } @@ -82,10 +128,12 @@ void dmxin_setup(void) { dmxin_class = class_new(gensym("dmxin"), (t_newmethod)dmxin_new, (t_method)dmxin_free, sizeof(t_dmxin), - CLASS_NOINLET, + 0, A_NULL); - + + class_addbang(dmxin_class, dmxin_bang); + #ifdef DMX4PD_POSTBANNER - DMX4PD_POSTBANNER + DMX4PD_POSTBANNER; #endif } -- cgit v1.2.1 From 3d0ac4fc230dfdebd5dcc1eaab4a7ad222279193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Mon, 16 Jun 2008 10:24:42 +0000 Subject: [dmxout] now can be used to set entire ranges svn path=/trunk/externals/iem/dmx512/; revision=10009 --- dmx512/README.txt | 61 ++++++++++++++ dmx512/dmx4linux2.6.1.patch | 196 ++++++++++++++++++++++++++++++++++++++++++++ dmx512/src/Make.config.in | 2 +- dmx512/src/Makefile | 2 +- dmx512/src/dmxout.c | 116 ++++++++++++++++++++------ 5 files changed, 348 insertions(+), 29 deletions(-) create mode 100644 dmx512/dmx4linux2.6.1.patch diff --git a/dmx512/README.txt b/dmx512/README.txt index 96579bc..7cb93f8 100644 --- a/dmx512/README.txt +++ b/dmx512/README.txt @@ -2,3 +2,64 @@ DMX512 ====== controlling DMX from within Pd + + + +A. setting up dmx4linux +======================= +note: there are debian(etch)-packages for dmx4linux, + but these seem to be pretty old (2.5) + i haven't really tried these. + instead i used dmx4linux-2.6.1 + +first get dmx4linux from http://llg.cubic.org/dmx4linux/ +and extract it. + +the drivers should compile fine with 2.6.18 kernels, but +alas! i am using 2.6.25 and there are some quirks to make +these work. + +first of all i had problems compiling the ISA/PCI/parport drivers, +but since i only wanted to use a USB device, i just disabled those. +second, dmx4linux's build-system tries to override CFLAGS when building +the kernel-modules, which newer kernel versions (e.g. 2.6.25) do not like +at all. i had to modify the makefiles in order to use the EXTRA_CFLAGS + +all the changes i did can be found in the dmx4linux2.6.1.patch +just run: +% patch -p1 < dmx4linux2.6.1.patch + +then do +% ./configure +(which will produce a /tmp/dmxconfig.mk) +and run +% make + +finally become root and do +# make install + + +load the appropriate kernel modules + + +B. permissions +the dmx device-files created by udev will be owned by root.root and not be +read/writeable by anyone but root. +in order to use them as an ordinary user, become root and create a group +"dmx" and add users who need access to the dmx-devices to this group: +# addgroup dmx +# adduser zmoelnig dmx + +in theory this should be enough to allow you access to your dmx devices +the next time you load a dmx-driver +if you have problems, try plugging your device out and in again + + + + + + + + + + diff --git a/dmx512/dmx4linux2.6.1.patch b/dmx512/dmx4linux2.6.1.patch new file mode 100644 index 0000000..842a3ba --- /dev/null +++ b/dmx512/dmx4linux2.6.1.patch @@ -0,0 +1,196 @@ +diff -Naur dmx4linux-2.6.1/configure dmx4linux-2.6.1.new/configure +--- dmx4linux-2.6.1/configure 2008-04-25 02:13:31.000000000 +0200 ++++ dmx4linux-2.6.1.new/configure 2008-06-14 16:56:21.000000000 +0200 +@@ -43,7 +43,7 @@ + + echo "AS31=$DMXROOT/tools/as31-unix" >> /tmp/dmxconfig.mk + +-echo "CFLAGS+=-Wall -O2 -I$DMXROOT/include" >> /tmp/dmxconfig.mk ++echo "DMX_CFLAGS+=-Wall -O2 -I$DMXROOT/include" >> /tmp/dmxconfig.mk + echo "LDFLAGS+=-L$DMXROOT/libs" >> /tmp/dmxconfig.mk + + if [ -f /usr/include/gpm.h -o -f /usr/local/include/gpm.h ] ; then +diff -Naur dmx4linux-2.6.1/drivers/devices/dgm/Makefile dmx4linux-2.6.1.new/drivers/devices/dgm/Makefile +--- dmx4linux-2.6.1/drivers/devices/dgm/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/dgm/Makefile 2008-06-14 16:53:25.000000000 +0200 +@@ -17,7 +17,7 @@ + endif + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/devices/isa/Makefile dmx4linux-2.6.1.new/drivers/devices/isa/Makefile +--- dmx4linux-2.6.1/drivers/devices/isa/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/isa/Makefile 2008-06-14 16:54:02.000000000 +0200 +@@ -5,7 +5,7 @@ + obj-m := dmxenlight.o + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/devices/isa/soundlight/Makefile dmx4linux-2.6.1.new/drivers/devices/isa/soundlight/Makefile +--- dmx4linux-2.6.1/drivers/devices/isa/soundlight/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/isa/soundlight/Makefile 2008-06-14 16:53:57.000000000 +0200 +@@ -4,7 +4,7 @@ + + ifneq ($(KERNELRELEASE),) + dmxsoundlight-objs=soundlight.o autoprobe.o slh_general.o slh1512a.o slh1512b.o slh1512c.o card_access.o +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + + $(src)/%.h : $(src)/%.asm + $(AS31)/as31 -Fbin -s $< | sh $(src)/bin2hex.sh $< > $@ +diff -Naur dmx4linux-2.6.1/drivers/devices/Makefile dmx4linux-2.6.1.new/drivers/devices/Makefile +--- dmx4linux-2.6.1/drivers/devices/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/Makefile 2008-06-14 16:58:50.000000000 +0200 +@@ -5,15 +5,15 @@ + ifneq ($(CONFIG_USB),) + $(MAKE) -C usb $@ + endif +-ifneq ($(CONFIG_ISA),) +- $(MAKE) -C isa $@ +-endif +-ifneq ($(CONFIG_PCI),) +- $(MAKE) -C pci $@ +-endif +-ifneq ($(CONFIG_PARPORT),) +- $(MAKE) -C parport $@ +-endif ++#ifneq ($(CONFIG_ISA),) ++# $(MAKE) -C isa $@ ++#endif ++#ifneq ($(CONFIG_PCI),) ++# $(MAKE) -C pci $@ ++#endif ++#ifneq ($(CONFIG_PARPORT),) ++# $(MAKE) -C parport $@ ++#endif + + # PCMCIA dmx drivers are currently not supported on 2.6 kernels + #ifneq ($(CONFIG_PCMCIA),) +diff -Naur dmx4linux-2.6.1/drivers/devices/misc/Makefile dmx4linux-2.6.1.new/drivers/devices/misc/Makefile +--- dmx4linux-2.6.1/drivers/devices/misc/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/misc/Makefile 2008-06-14 16:54:07.000000000 +0200 +@@ -3,7 +3,7 @@ + obj-m := dmxdummy.o + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/devices/parport/Makefile dmx4linux-2.6.1.new/drivers/devices/parport/Makefile +--- dmx4linux-2.6.1/drivers/devices/parport/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/parport/Makefile 2008-06-14 16:53:52.000000000 +0200 +@@ -5,7 +5,7 @@ + obj-m := avrdmx.o dmx30.o dmx43.o dmxpcp.o okddmx.o lpr2dmx.o + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/devices/pci/Makefile dmx4linux-2.6.1.new/drivers/devices/pci/Makefile +--- dmx4linux-2.6.1/drivers/devices/pci/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/pci/Makefile 2008-06-14 16:53:47.000000000 +0200 +@@ -5,7 +5,7 @@ + obj-m += slh1514pci.o + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" -DDMXPCI_DMX4LINUX=1 ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" -DDMXPCI_DMX4LINUX=1 $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/devices/pcmcia/Makefile dmx4linux-2.6.1.new/drivers/devices/pcmcia/Makefile +--- dmx4linux-2.6.1/drivers/devices/pcmcia/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/pcmcia/Makefile 2008-06-14 16:53:38.000000000 +0200 +@@ -5,7 +5,7 @@ + obj-m += digimedia_cs.o + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/devices/usb/Makefile dmx4linux-2.6.1.new/drivers/devices/usb/Makefile +--- dmx4linux-2.6.1/drivers/devices/usb/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/devices/usb/Makefile 2008-06-14 16:53:14.000000000 +0200 +@@ -5,7 +5,7 @@ + obj-m := usb2dmx.o ftdi2dmx.o sunlite.o + + ifneq ($(KERNELRELEASE),) +-EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" ++EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" $(DMX_CFLAGS) + else + + PWD := $(shell pwd) +diff -Naur dmx4linux-2.6.1/drivers/dmxdev/Makefile dmx4linux-2.6.1.new/drivers/dmxdev/Makefile +--- dmx4linux-2.6.1/drivers/dmxdev/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/drivers/dmxdev/Makefile 2008-06-14 16:54:22.000000000 +0200 +@@ -8,7 +8,8 @@ + dmxdev-objs:=dmx_dev.o dmx_proc.o dmx_props.o dmx_family.o dmx_driver.o dmx_interface.o dmx_universe.o dmx_fileinfo.o + EXTRA_CFLAGS:=-DDMXVERSION=\"${DMXVERSION}\" \ + -DDMXOUTMINOR=$(DMXOUTMINOR) -DDMXINMINOR=$(DMXINMINOR) \ +- -DVERSIONMAJOR=$(VERSIONMAJOR) -DVERSIONMINOR=$(VERSIONMINOR) ++ -DVERSIONMAJOR=$(VERSIONMAJOR) -DVERSIONMINOR=$(VERSIONMINOR) \ ++ $(DMX_CFLAGS) + + else + +diff -Naur dmx4linux-2.6.1/examples/htmlexamples/Makefile dmx4linux-2.6.1.new/examples/htmlexamples/Makefile +--- dmx4linux-2.6.1/examples/htmlexamples/Makefile 2008-04-25 02:13:31.000000000 +0200 ++++ dmx4linux-2.6.1.new/examples/htmlexamples/Makefile 2008-06-14 16:54:42.000000000 +0200 +@@ -2,7 +2,7 @@ + + TARGETS= nonblockread selectread simpleread simplewrite + +-CFLAGS+= -Wall ++CFLAGS+= $(DMX_CFLAGS) -Wall + + all: $(TARGETS) + +diff -Naur dmx4linux-2.6.1/examples/Makefile dmx4linux-2.6.1.new/examples/Makefile +--- dmx4linux-2.6.1/examples/Makefile 2008-04-25 02:13:31.000000000 +0200 ++++ dmx4linux-2.6.1.new/examples/Makefile 2008-06-14 17:00:15.000000000 +0200 +@@ -6,6 +6,8 @@ + + -include /tmp/dmxconfig.mk + ++CFLAGS += $(DMX_CFLAGS) ++ + TARGETS= pingdmx setdmx dmxinfo dmxdump + + all: $(TARGETS) +diff -Naur dmx4linux-2.6.1/tools/Makefile dmx4linux-2.6.1.new/tools/Makefile +--- dmx4linux-2.6.1/tools/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/tools/Makefile 2008-06-14 16:55:16.000000000 +0200 +@@ -4,7 +4,7 @@ + MANINSTALLPATH=$(DMXPREFIX)/man/man1 + + DMXCONSOLELIBS+= -Lpointer pointer/pointer.a +-CFLAGS+= -Ipointer ++CFLAGS+= -Ipointer $(DMX_CFLAGS) + + ifdef CONFIG_HAVE_LIRC + CFLAGS+= -DHAVE_LIRC=1 +diff -Naur dmx4linux-2.6.1/tools/pointer/Makefile dmx4linux-2.6.1.new/tools/pointer/Makefile +--- dmx4linux-2.6.1/tools/pointer/Makefile 2008-04-25 02:13:32.000000000 +0200 ++++ dmx4linux-2.6.1.new/tools/pointer/Makefile 2008-06-14 16:59:35.000000000 +0200 +@@ -1,5 +1,7 @@ + -include /tmp/dmxconfig.mk + ++CFLAGS+=$(DMX_CFLAGS) ++ + C= js.c pointer.c ps2.c serial.c + ifdef CONFIG_HAVE_GPM + C+= gpm.c diff --git a/dmx512/src/Make.config.in b/dmx512/src/Make.config.in index d3ac25f..3386e58 100644 --- a/dmx512/src/Make.config.in +++ b/dmx512/src/Make.config.in @@ -25,7 +25,7 @@ TARNAME = $(LIBNAME)-$(VERSION).tgz BINTARNAME = $(LIBNAME)-$(VERSION)-bin.tgz -CFLAGS = $(DEFS) $(IFLAGS) $(WFLAGS) @CFLAGS@ +DMX4PD_CFLAGS = $(DEFS) $(IFLAGS) $(WFLAGS) @CFLAGS@ LIBS = @LIBS@ diff --git a/dmx512/src/Makefile b/dmx512/src/Makefile index e634df6..36b92bc 100644 --- a/dmx512/src/Makefile +++ b/dmx512/src/Makefile @@ -67,7 +67,7 @@ ifeq (,$(findstring clean, $(MAKECMDGOALS))) -include $(SOURCES:.c=.d) %.d: %.c @set -e; rm -f $@; \ - $(CC) $(MAKEDEP_FLAGS) $(CFLAGS) $< > $@.$$$$; \ + $(CC) $(MAKEDEP_FLAGS) $(DMX4PD_CFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index 08d70b2..6066567 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -21,6 +21,7 @@ #include static t_class *dmxout_class; +static t_class *dmxout_class2; typedef struct _dmxout { @@ -30,6 +31,7 @@ typedef struct _dmxout int x_device; t_float x_port; + int x_portrange; } t_dmxout; @@ -64,16 +66,21 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) } } -static void dmxout_doout(t_dmxout*x, short port, unsigned char value) +static void dmxout_doout(t_dmxout*x, short baseport, short portrange, dmx_t*values) { - dmx_t buffer[1] = {value}; if(x->x_device<=0) { pd_error(x, "no DMX universe found"); return; } - lseek (x->x_device, sizeof(buffer)*port, SEEK_SET); /* set to the current channel */ - write (x->x_device, buffer, sizeof(buffer)); /* write the channel */ + lseek (x->x_device, sizeof(dmx_t)*baseport, SEEK_SET); /* set to the current channel */ + write (x->x_device, values, portrange*sizeof(dmx_t)); /* write the channel */ +} + +static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) +{ + dmx_t buffer[1] = {value}; + dmxout_doout(x, port, 1, buffer); } @@ -90,42 +97,86 @@ static void dmxout_float(t_dmxout*x, t_float f) return; } - dmxout_doout(x, port, val); + dmxout_doout1(x, port, val); } -static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) +static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) +{ + int count=(argcx_portrange)?argc:x->x_portrange; + dmx_t*buffer=(dmx_t*)getbytes(count*sizeof(dmx_t)); + int i=0; + + int errors=0; + + for(i=0; i255.) { + errors++; + if(f<0.)f=0.; + if(f>255)f=255; + } + buffer[i]=(unsigned char)f; + } + if(errors) { + pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); + } + + dmxout_doout(x, x->x_port, count, buffer); +} + +static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) { - t_dmxout *x = (t_dmxout *)pd_new(dmxout_class); + short baseport =(short)f_baseport; + short portrange=(short)f_portrange; - t_symbol*devname=gensym(""); - x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); + if(baseport<0 || baseport>=512) { + pd_error(x, "port %f out of bounds [0..512]", f_baseport); + baseport =0; + } + x->x_port = baseport; - x->x_device=-1; - x->x_port =0; + if(portrange<0) { + pd_error(x, "portrange %f<0! setting to 1", portrange); + portrange=1; + } else if (portrange==0) { + portrange=x->x_portrange; + } + + if (baseport+portrange>512) { + pd_error(x, "upper port exceeds 512! clamping"); + portrange=512-baseport; + } + x->x_portrange=portrange; +} + +static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) +{ + t_floatarg baseport=0.f, portrange=0.f; + t_dmxout *x = 0; switch(argc) { - case 0: break; + case 2: + x=(t_dmxout *)pd_new(dmxout_class2); + x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); + baseport=atom_getfloat(argv); + portrange=atom_getfloat(argv+1); + dmxout_port(x, baseport, portrange); + break; case 1: - if(A_FLOAT==argv->a_type) { - x->x_port=atom_getfloat(argv); - } else { - devname=atom_getsymbol(argv); - } + baseport=atom_getfloat(argv); + case 0: + x=(t_dmxout *)pd_new(dmxout_class); + x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); + x->x_port = baseport; + x->x_portrange = -1; break; default: - if((A_FLOAT==(argv+0)->a_type) && (A_SYMBOL==(argv+1)->a_type)) { - x->x_port=atom_getfloat(argv+0); - devname=atom_getsymbol(argv+1); - } else if(A_FLOAT==(argv+1)->a_type && A_SYMBOL==(argv+0)->a_type) { - x->x_port=atom_getfloat(argv+1); - devname=atom_getsymbol (argv+0); - } - break; + return 0; } + x->x_device=-1; - - dmxout_open(x, devname); + dmxout_open(x, gensym("")); return (x); } @@ -144,6 +195,17 @@ void dmxout_setup(void) class_addfloat(dmxout_class, dmxout_float); + dmxout_class2 = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, + sizeof(t_dmxout), + 0, + A_GIMME, A_NULL); + + class_addlist(dmxout_class2, dmxout_list); + + + class_addmethod(dmxout_class2, (t_method)dmxout_port, gensym("port"), + A_FLOAT, A_DEFFLOAT, A_NULL); + #ifdef DMX4PD_POSTBANNER DMX4PD_POSTBANNER #endif -- cgit v1.2.1 From 2dd16c5ca5fe4ccfc995f23df1b752299108a488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Thu, 19 Jun 2008 13:14:39 +0000 Subject: updated readme.txt like vincent rioux suggested; fixed configure to also search for libdmx4l (which is the library installed by he upstream dmx4linux package) svn path=/trunk/externals/iem/dmx512/; revision=10044 --- dmx512/README.txt | 22 +++++++++++++++++++++- dmx512/src/configure.ac | 12 ++++-------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/dmx512/README.txt b/dmx512/README.txt index 7cb93f8..3eda9d8 100644 --- a/dmx512/README.txt +++ b/dmx512/README.txt @@ -38,11 +38,14 @@ and run finally become root and do # make install +after all has gone well, load the appropriate kernel modules -load the appropriate kernel modules + +btw, it is always a good idea to read the readme that comes with dmx4linux... B. permissions +============== the dmx device-files created by udev will be owned by root.root and not be read/writeable by anyone but root. in order to use them as an ordinary user, become root and create a group @@ -55,9 +58,26 @@ the next time you load a dmx-driver if you have problems, try plugging your device out and in again +C. compiling the Pd-objects +=========================== +so now it is time to get the Pd-objects going. +for this change into the "./src" directory of the iem/dmx512/ folder +(this might well be the folder that holds this README.txt you are currently +reading) + +if you have obtained the source-code via subversion, you will first have to run +% autoconf +(this should not be needed if you downloaded the sources as a release tarball; +that is: if the person who created the tarball has not forgotten to do it for you) + +then run +% configure +% make +you should now have 2 binary files in the src/ folder called [dmxin] and [dmxout] +go on and use em! diff --git a/dmx512/src/configure.ac b/dmx512/src/configure.ac index ce4dc98..eff616a 100644 --- a/dmx512/src/configure.ac +++ b/dmx512/src/configure.ac @@ -39,15 +39,11 @@ dnl Replace `main' with a function in -lstk: dnl AC_CHECK_LIB(stk, main, STK=yes) +AC_CHECK_LIB(dmx4l, DMXsleep) AC_CHECK_LIB(dmx4linux, DMXsleep) -if test "x$ac_cv_lib_dmx4linux_DMXsleep" = "xyes"; then - DMX4LINUX_LFLAGS="-ldmx4linux" -fi - -dnl AC_CHECK_LIB(asound, snd_seq_close) -dnl if test "x$ac_cv_lib_asound_snd_seq_close" = "xyes"; then -dnl DFLAGS="-DHAVE_ALSA ${DFLAGS}" -dnl fi +#if test "x$ac_cv_lib_dmx4linux_DMXsleep" = "xyes"; then +# DMX4LINUX_LFLAGS="-ldmx4linux" +#fi if test "x$includedir" != "x"; then for id in $includedir -- cgit v1.2.1 From 3b275827ce30bc37dd33ea83448d3fb8d560c40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Thu, 19 Jun 2008 13:29:33 +0000 Subject: added help-patch for [dmxout] svn path=/trunk/externals/iem/dmx512/; revision=10045 --- dmx512/help/dmxout-help.pd | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 dmx512/help/dmxout-help.pd diff --git a/dmx512/help/dmxout-help.pd b/dmx512/help/dmxout-help.pd new file mode 100644 index 0000000..36f8c6c --- /dev/null +++ b/dmx512/help/dmxout-help.pd @@ -0,0 +1,36 @@ +#N canvas 0 0 719 485 10; +#X obj 102 31 dmxout; +#X text 158 31 control DMX512-devices from within Pd; +#X text 85 106 DMX512 is a protocol for controlling lights and magic +\, similar to MIDI; +#X obj 62 240 dmxout; +#X floatatom 62 171 5 0 255 1 value - -; +#X floatatom 101 195 5 0 255 1 channel - -; +#X floatatom 232 171 5 0 255 1 value - -; +#X obj 232 240 dmxout 5; +#X text 232 261 default channel: 5; +#X obj 402 270 dmxout 5 4; +#X text 402 291 default channel: 5 6 7 8; +#X msg 402 169 \$1 100 \$1 100; +#X text 502 170 4 values \, one for each channel; +#X floatatom 402 151 5 0 255 1 value - -; +#X msg 488 239 6; +#X text 518 241 channels 6 7 ...; +#X msg 469 202 10 3; +#X text 504 201 channels 10 11 12; +#X text 80 336 [dmxout] is currently linux only. ports to other OSs +are desired but not high priority.; +#X text 80 378 by default \, [dmxout] will try to open the device /dev/dmx +; +#X text 79 401 you can change the default dmx-device globally by setting +the "DMX" environment variable prior to creating the [dmxout] object +(e.g. before you start Pd); +#X text 501 34 (c) 2008 IOhannes m zmölnig; +#X text 559 53 iem @ KUG; +#X connect 4 0 3 0; +#X connect 5 0 3 1; +#X connect 6 0 7 0; +#X connect 11 0 9 0; +#X connect 13 0 11 0; +#X connect 14 0 9 1; +#X connect 16 0 9 1; -- cgit v1.2.1 From 6eacde1fb5eb79d68e5c699ab69d1cec73b23791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 20 Jun 2008 15:33:18 +0000 Subject: hmm, fixed a problem; seems to work now with an openDMX-USB svn path=/trunk/externals/iem/dmx512/; revision=10056 --- dmx512/src/dmxout.c | 51 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index 6066567..dcfef75 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -33,8 +33,16 @@ typedef struct _dmxout t_float x_port; int x_portrange; + dmx_t x_values[512]; + } t_dmxout; +static void dmxout_clearbuf(t_dmxout*x) +{ + int i=0; + for(i=0; i<512; i++) x->x_values[i]=0; +} + static void dmxout_close(t_dmxout*x) { if(x->x_device>=0) { @@ -49,7 +57,7 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) int argc=2; const char *args[2] = {"--dmx", s_devname->s_name}; const char**argv=args; - char*devname=""; + const char*devname=""; int fd; if(s_devname && s_devname->s_name) @@ -57,8 +65,14 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) // strncpy(args[0], "--dmx", MAXPDSTRING); // strncpy(args[1], devname, MAXPDSTRING); + devname=DMXdev(&argc, argv); + if(!devname){ + pd_error(x, "couldn't find DMX device"); + return; + } + verbose(1, "[dmxout] opening %s", devname); - fd = open (DMXdev(&argc, argv), O_WRONLY); + fd = open (devname, O_WRONLY); if(fd!=-1) { dmxout_close(x); @@ -66,21 +80,29 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) } } -static void dmxout_doout(t_dmxout*x, short baseport, short portrange, dmx_t*values) +static void dmxout_doout(t_dmxout*x, dmx_t values[512]) { + int i; if(x->x_device<=0) { pd_error(x, "no DMX universe found"); return; } +#if 0 + for(i=0; i<512; i++) { + post("dmx[%d]=%03d", i, values[i]); + } + endpost(); +#endif - lseek (x->x_device, sizeof(dmx_t)*baseport, SEEK_SET); /* set to the current channel */ - write (x->x_device, values, portrange*sizeof(dmx_t)); /* write the channel */ + lseek (x->x_device, 0, SEEK_SET); /* set to the current channel */ + write (x->x_device, values, 512); /* write the channel */ } static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) { - dmx_t buffer[1] = {value}; - dmxout_doout(x, port, 1, buffer); + dmxout_clearbuf(x); + x->x_values[port]=value; + dmxout_doout(x, x->x_values); } @@ -103,11 +125,18 @@ static void dmxout_float(t_dmxout*x, t_float f) static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) { int count=(argcx_portrange)?argc:x->x_portrange; - dmx_t*buffer=(dmx_t*)getbytes(count*sizeof(dmx_t)); int i=0; - int errors=0; + int port=x->x_port; + if((port+count)>=512) { + if(count>512)count=512; + port=512-count; + } + + dmxout_clearbuf(x); + + for(i=0; i255.) { @@ -115,13 +144,13 @@ static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) if(f<0.)f=0.; if(f>255)f=255; } - buffer[i]=(unsigned char)f; + x->x_values[port+i]=(unsigned char)f; } if(errors) { pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); } - dmxout_doout(x, x->x_port, count, buffer); + dmxout_doout(x, x->x_values); } static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) -- cgit v1.2.1 From caaefca7ebe5a15d99f358b68dd84a7ad47bd317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Mon, 30 Jun 2008 10:45:57 +0000 Subject: ... svn path=/trunk/externals/iem/dmx512/; revision=10117 --- dmx512/README.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dmx512/README.txt b/dmx512/README.txt index 3eda9d8..346934e 100644 --- a/dmx512/README.txt +++ b/dmx512/README.txt @@ -57,6 +57,9 @@ in theory this should be enough to allow you access to your dmx devices the next time you load a dmx-driver if you have problems, try plugging your device out and in again +if you don't care for a clean setup, you could also just grant everyone read/write permissions. +this might be a security risk. + C. compiling the Pd-objects =========================== -- cgit v1.2.1 From 0743593e7adec852e293e5e42d851256c225cd74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Mon, 30 Jun 2008 11:01:03 +0000 Subject: split the readme into several files svn path=/trunk/externals/iem/dmx512/; revision=10118 --- dmx512/FAQ.txt | 2 ++ dmx512/README.dmx4linux.txt | 79 +++++++++++++++++++++++++++++++++++++++++++ dmx512/README.txt | 82 ++++++++++++--------------------------------- 3 files changed, 102 insertions(+), 61 deletions(-) create mode 100644 dmx512/FAQ.txt create mode 100644 dmx512/README.dmx4linux.txt diff --git a/dmx512/FAQ.txt b/dmx512/FAQ.txt new file mode 100644 index 0000000..484dc8a --- /dev/null +++ b/dmx512/FAQ.txt @@ -0,0 +1,2 @@ +Q: Where do I find answers to questions not answered here? +A: try the "Pure Data" community mailinglist http://lists.puredata.info diff --git a/dmx512/README.dmx4linux.txt b/dmx512/README.dmx4linux.txt new file mode 100644 index 0000000..94c5bfc --- /dev/null +++ b/dmx512/README.dmx4linux.txt @@ -0,0 +1,79 @@ +DMX512 +====== + +THIS IS NOT A DOCUMENTATION. +NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED! + +these are just random notes on what i found useful in getting dmx4linux running. +it might freeze your computer or boil your lights. + + +A. setting up dmx4linux +======================= +note: there are debian(etch)-packages for dmx4linux, + but these seem to be pretty old (2.5) + i haven't really tried these. + instead i used dmx4linux-2.6.1 + +first get dmx4linux from http://llg.cubic.org/dmx4linux/ +and extract it. + +the drivers should compile fine with 2.6.18 kernels, but +alas! i am using 2.6.25 and there are some quirks to make +these work. + +first of all i had problems compiling the ISA/PCI/parport drivers, +but since i only wanted to use a USB device, i just disabled those. +second, dmx4linux's build-system tries to override CFLAGS when building +the kernel-modules, which newer kernel versions (e.g. 2.6.25) do not like +at all. i had to modify the makefiles in order to use the EXTRA_CFLAGS + +all the changes i did can be found in the dmx4linux2.6.1.patch +just run: +% patch -p1 < dmx4linux2.6.1.patch + +then do +% ./configure +(which will produce a /tmp/dmxconfig.mk) +and run +% make + +finally become root and do +# make install + +after all has gone well, load the appropriate kernel modules + + +btw, it is always a good idea to read the readme that comes with dmx4linux... + + +B. permissions +============== +the dmx device-files created by udev will be owned by root.root and not be +read/writeable by anyone but root. +in order to use them as an ordinary user, become root and create a group +"dmx" and add users who need access to the dmx-devices to this group: +# addgroup dmx +# adduser zmoelnig dmx + +in theory this should be enough to allow you access to your dmx devices +the next time you load a dmx-driver +if you have problems, try plugging your device out and in again + +if you don't care for a clean setup, you could also just grant everyone read/write permissions. +# chmod a+rw /dev/dmx* +be aware that this might be a security risk. + + + +C. more drivers +=============== +for using a "JMS USB2DMX" device, i had some driver problems. +finally i found +http://www.opendmx.net/index.php/Linux_ArtNet_Node +which directed me to +http://www.erwinrol.com/index.php?opensource/dmxusb.php +and the "dmx_usb" module which seems to work fine. +i guess, it will also work for the "enttec opendmx" device + + diff --git a/dmx512/README.txt b/dmx512/README.txt index 346934e..327c744 100644 --- a/dmx512/README.txt +++ b/dmx512/README.txt @@ -3,68 +3,13 @@ DMX512 controlling DMX from within Pd +this readme assumes that you have a running dmx4linux setup. +if not, read the README.dmx4linux.txt file for hints on how to +get it going... - -A. setting up dmx4linux -======================= -note: there are debian(etch)-packages for dmx4linux, - but these seem to be pretty old (2.5) - i haven't really tried these. - instead i used dmx4linux-2.6.1 - -first get dmx4linux from http://llg.cubic.org/dmx4linux/ -and extract it. - -the drivers should compile fine with 2.6.18 kernels, but -alas! i am using 2.6.25 and there are some quirks to make -these work. - -first of all i had problems compiling the ISA/PCI/parport drivers, -but since i only wanted to use a USB device, i just disabled those. -second, dmx4linux's build-system tries to override CFLAGS when building -the kernel-modules, which newer kernel versions (e.g. 2.6.25) do not like -at all. i had to modify the makefiles in order to use the EXTRA_CFLAGS - -all the changes i did can be found in the dmx4linux2.6.1.patch -just run: -% patch -p1 < dmx4linux2.6.1.patch - -then do -% ./configure -(which will produce a /tmp/dmxconfig.mk) -and run -% make - -finally become root and do -# make install - -after all has gone well, load the appropriate kernel modules - - -btw, it is always a good idea to read the readme that comes with dmx4linux... - - -B. permissions -============== -the dmx device-files created by udev will be owned by root.root and not be -read/writeable by anyone but root. -in order to use them as an ordinary user, become root and create a group -"dmx" and add users who need access to the dmx-devices to this group: -# addgroup dmx -# adduser zmoelnig dmx - -in theory this should be enough to allow you access to your dmx devices -the next time you load a dmx-driver -if you have problems, try plugging your device out and in again - -if you don't care for a clean setup, you could also just grant everyone read/write permissions. -this might be a security risk. - - -C. compiling the Pd-objects +A. compiling the Pd-objects =========================== -so now it is time to get the Pd-objects going. -for this change into the "./src" directory of the iem/dmx512/ folder +for this, change into the "./src" directory of the iem/dmx512/ folder (this might well be the folder that holds this README.txt you are currently reading) @@ -80,9 +25,24 @@ then run you should now have 2 binary files in the src/ folder called [dmxin] and [dmxout] -go on and use em! +B. Installation +=============== +you should install the binaries (+helpfiles) somewhere Pd can find them. +i would suggest to put them into + /extra/dmx512/ +and add this path to the startup-flags of Pd. + + +C. Usage +======== +there should be help-files in the ./help directory +if not, the useage should be very similar to that of [ctlin] and [ctlout] +(it's just using DMX512 instead of MIDI) +D. Help! +======== +read the FAQ -- cgit v1.2.1 From f272f82bd7d8f6ec25e292e8ac92b81d4623901a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Mon, 30 Jun 2008 11:13:10 +0000 Subject: added "open"-mess (not functional yet) to change the device... svn path=/trunk/externals/iem/dmx512/; revision=10119 --- dmx512/src/dmx4pd.h | 4 ++-- dmx512/src/dmxout.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dmx512/src/dmx4pd.h b/dmx512/src/dmx4pd.h index cc6fe66..059c794 100644 --- a/dmx512/src/dmx4pd.h +++ b/dmx512/src/dmx4pd.h @@ -33,9 +33,9 @@ #define DMX4PD_POSTBANNER \ - { \ + do { \ post("DMX4PD ("DMX4PD_VERSION"): (c) 2008 IOhannes m zmölnig - iem @ kug"); \ - } + } while(0) #endif /* INCLUDE_DMX4PD_H__ */ diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index dcfef75..9c4c7fe 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -65,6 +65,7 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) // strncpy(args[0], "--dmx", MAXPDSTRING); // strncpy(args[1], devname, MAXPDSTRING); + verbose(2, "[dmxout]: trying to open '%s'", args[1]); devname=DMXdev(&argc, argv); if(!devname){ pd_error(x, "couldn't find DMX device"); @@ -77,6 +78,8 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) if(fd!=-1) { dmxout_close(x); x->x_device=fd; + } else { + error("failed to open DMX-device '%s'",devname); } } @@ -217,12 +220,17 @@ static void *dmxout_free(t_dmxout*x) void dmxout_setup(void) { +#ifdef DMX4PD_POSTBANNER + DMX4PD_POSTBANNER; +#endif + dmxout_class = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, sizeof(t_dmxout), 0, A_GIMME, A_NULL); class_addfloat(dmxout_class, dmxout_float); + class_addmethod(dmxout_class, (t_method)dmxout_open, gensym("open"), A_SYMBOL, A_NULL); dmxout_class2 = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, sizeof(t_dmxout), @@ -235,7 +243,5 @@ void dmxout_setup(void) class_addmethod(dmxout_class2, (t_method)dmxout_port, gensym("port"), A_FLOAT, A_DEFFLOAT, A_NULL); -#ifdef DMX4PD_POSTBANNER - DMX4PD_POSTBANNER -#endif + class_addmethod(dmxout_class2, (t_method)dmxout_open, gensym("open"), A_SYMBOL, A_NULL); } -- cgit v1.2.1 From 8a92ec9b79cf44f14ebaf517bc19e76e4d111233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Tue, 1 Jul 2008 09:56:21 +0000 Subject: number of values is now a preprocessor define (so we can easily change it: dmx4linux seems to be way faster with small (<128) valuearrays) svn path=/trunk/externals/iem/dmx512/; revision=10127 --- dmx512/src/dmxout.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index 9c4c7fe..83f5260 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -23,6 +23,8 @@ static t_class *dmxout_class; static t_class *dmxout_class2; +#define NUM_DMXVALUES 512 + typedef struct _dmxout { t_object x_obj; @@ -33,14 +35,14 @@ typedef struct _dmxout t_float x_port; int x_portrange; - dmx_t x_values[512]; + dmx_t x_values[NUM_DMXVALUES]; } t_dmxout; static void dmxout_clearbuf(t_dmxout*x) { int i=0; - for(i=0; i<512; i++) x->x_values[i]=0; + for(i=0; ix_values[i]=0; } static void dmxout_close(t_dmxout*x) @@ -83,7 +85,7 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) } } -static void dmxout_doout(t_dmxout*x, dmx_t values[512]) +static void dmxout_doout(t_dmxout*x, dmx_t values[NUM_DMXVALUES]) { int i; if(x->x_device<=0) { @@ -91,14 +93,14 @@ static void dmxout_doout(t_dmxout*x, dmx_t values[512]) return; } #if 0 - for(i=0; i<512; i++) { + for(i=0; ix_device, 0, SEEK_SET); /* set to the current channel */ - write (x->x_device, values, 512); /* write the channel */ + write (x->x_device, values, NUM_DMXVALUES); /* write the channel */ } static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) @@ -117,8 +119,8 @@ static void dmxout_float(t_dmxout*x, t_float f) pd_error(x, "value %f out of bounds [0..255]", f); return; } - if(x->x_port<0. || x->x_port>512.) { - pd_error(x, "port %f out of bounds [0..512]", x->x_port); + if(x->x_port<0. || x->x_port>NUM_DMXVALUES) { + pd_error(x, "port %f out of bounds [0..%d]", x->x_port, NUM_DMXVALUES); return; } @@ -132,9 +134,9 @@ static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) int errors=0; int port=x->x_port; - if((port+count)>=512) { - if(count>512)count=512; - port=512-count; + if((port+count)>=NUM_DMXVALUES) { + if(count>NUM_DMXVALUES)count=NUM_DMXVALUES; + port=NUM_DMXVALUES-count; } dmxout_clearbuf(x); @@ -162,8 +164,8 @@ static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) short portrange=(short)f_portrange; - if(baseport<0 || baseport>=512) { - pd_error(x, "port %f out of bounds [0..512]", f_baseport); + if(baseport<0 || baseport>=NUM_DMXVALUES) { + pd_error(x, "port %f out of bounds [0..%d]", f_baseport, NUM_DMXVALUES); baseport =0; } x->x_port = baseport; @@ -175,9 +177,9 @@ static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) portrange=x->x_portrange; } - if (baseport+portrange>512) { - pd_error(x, "upper port exceeds 512! clamping"); - portrange=512-baseport; + if (baseport+portrange>NUM_DMXVALUES) { + pd_error(x, "upper port exceeds %d! clamping", NUM_DMXVALUES); + portrange=NUM_DMXVALUES-baseport; } x->x_portrange=portrange; } -- cgit v1.2.1 From be5bf77657bdf9a55ba2ab3ef0ddd1be90038458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Wed, 2 Jul 2008 11:31:27 +0000 Subject: cleaned up a bit svn path=/trunk/externals/iem/dmx512/; revision=10131 --- dmx512/src/dmxout.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index 83f5260..968110d 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -14,11 +14,11 @@ * ******************************************************/ - #include "dmx4pd.h" #include #include +#include static t_class *dmxout_class; static t_class *dmxout_class2; @@ -36,7 +36,6 @@ typedef struct _dmxout int x_portrange; dmx_t x_values[NUM_DMXVALUES]; - } t_dmxout; static void dmxout_clearbuf(t_dmxout*x) @@ -62,6 +61,8 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) const char*devname=""; int fd; + dmxout_close(x); + if(s_devname && s_devname->s_name) devname=s_devname->s_name; @@ -75,39 +76,32 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) } verbose(1, "[dmxout] opening %s", devname); - fd = open (devname, O_WRONLY); + fd = open (devname, O_WRONLY | O_NONBLOCK); if(fd!=-1) { - dmxout_close(x); x->x_device=fd; + dmxout_clearbuf(x); } else { - error("failed to open DMX-device '%s'",devname); + pd_error(x, "failed to open DMX-device '%s'",devname); } } -static void dmxout_doout(t_dmxout*x, dmx_t values[NUM_DMXVALUES]) -{ - int i; - if(x->x_device<=0) { +static void dmxout_doout(t_dmxout*x) { + int device = x->x_device; + if(device<=0) { pd_error(x, "no DMX universe found"); return; } -#if 0 - for(i=0; ix_device, 0, SEEK_SET); /* set to the current channel */ - write (x->x_device, values, NUM_DMXVALUES); /* write the channel */ + lseek (device, 0, SEEK_SET); /* set to the current channel */ + write (device, x->x_values, NUM_DMXVALUES); /* write the channel */ } + static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) { - dmxout_clearbuf(x); x->x_values[port]=value; - dmxout_doout(x, x->x_values); + dmxout_doout(x); } @@ -139,9 +133,6 @@ static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) port=NUM_DMXVALUES-count; } - dmxout_clearbuf(x); - - for(i=0; i255.) { @@ -155,7 +146,7 @@ static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); } - dmxout_doout(x, x->x_values); + dmxout_doout(x); } static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) -- cgit v1.2.1 From eca3d9fda4d27f749cce9232aac71f4363e1bd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Wed, 2 Jul 2008 11:33:21 +0000 Subject: a threaded version of [dmxout]: this should become the default svn path=/trunk/externals/iem/dmx512/; revision=10132 --- dmx512/src/dmxout_threaded.c | 302 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 dmx512/src/dmxout_threaded.c diff --git a/dmx512/src/dmxout_threaded.c b/dmx512/src/dmxout_threaded.c new file mode 100644 index 0000000..a35fb1b --- /dev/null +++ b/dmx512/src/dmxout_threaded.c @@ -0,0 +1,302 @@ +/****************************************************** + * + * dmxout_threaded - implementation file + * + * copyleft (c) IOhannes m zmölnig + * + * 0603:forum::für::umläute:2008 + * + * institute of electronic music and acoustics (iem) + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#include "dmx4pd.h" + +#include +#include +#include + +#include + + +static t_class *dmxout_threaded_class; +static t_class *dmxout_threaded_class2; + +#define NUM_DMXVALUES 512 + +static pthread_t g_thread_id; +static pthread_mutex_t *g_mutex; +static dmx_t g_values[NUM_DMXVALUES]; +static int g_device; +static int g_thread_running, g_thread_continue; + +typedef struct _dmxout_threaded +{ + t_object x_obj; + + t_inlet *x_portinlet; + t_float x_port; + int x_portrange; + + +} t_dmxout_threaded; + + +static void *dmxout_threaded_thread(void*you) +{ + pthread_mutex_t *mutex=g_mutex; + struct timeval timout; + + g_thread_running=1; + + while(g_thread_continue) { + timout.tv_sec = 0; + timout.tv_usec=100; + select(0,0,0,0,&timout); + + pthread_mutex_lock(g_mutex); + if(g_device>0) { + lseek (g_device, 0, SEEK_SET); /* set to the current channel */ + write (g_device, g_values, NUM_DMXVALUES); /* write the channel */ + } + pthread_mutex_unlock(g_mutex); + } + g_thread_running=0; + printf("quit thread"); + + return NULL; +} + +static void dmxout_threaded_close() +{ + if(g_device>=0) { + close(g_device); + } + g_device=-1; + + if(g_thread_running) { + /* terminate the current thread! */ + void*dummy=0; + int counter=0; + g_thread_continue=0; + pthread_join(g_thread_id, &dummy); + while(g_thread_running) { + counter++; + } + } + g_thread_id=0; + if(g_mutex) { + pthread_mutex_destroy(g_mutex); + freebytes(g_mutex, sizeof(pthread_mutex_t)); + g_mutex=NULL; + } +} + + +static void dmxout_threaded_open(t_symbol*s_devname) +{ + int argc=2; + const char *args[2] = {"--dmx", s_devname->s_name}; + const char**argv=args; + const char*devname=""; + int fd; + + dmxout_threaded_close(); + + if(s_devname && s_devname->s_name) + devname=s_devname->s_name; + + // strncpy(args[0], "--dmx", MAXPDSTRING); + // strncpy(args[1], devname, MAXPDSTRING); + verbose(2, "[dmxout_threaded]: trying to open '%s'", args[1]); + devname=DMXdev(&argc, argv); + if(!devname){ + error("couldn't find DMX device"); + return; + } + verbose(1, "[dmxout_threaded] opening %s", devname); + + fd = open (devname, O_WRONLY); + + if(fd!=-1) { + g_device=fd; + + g_thread_running=0; + g_thread_continue=0; + g_mutex=(pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); + if ( pthread_mutex_init(g_mutex, NULL) < 0 ) { + error("couldn't create mutex"); + } else { + g_thread_continue = 1; + pthread_create(&g_thread_id, 0, dmxout_threaded_thread, NULL); + } + } else { + error("failed to open DMX-device '%s'",devname); + } +} + +static void dmxout_threaded_doout(t_dmxout_threaded*x) { + if(g_device<=0) { + pd_error(x, "no DMX universe found"); + return; + } +} + + +static void dmxout_threaded_doout1(t_dmxout_threaded*x, short port, unsigned char value) +{ + g_values[port]=value; + dmxout_threaded_doout(x); +} + + +static void dmxout_threaded_float(t_dmxout_threaded*x, t_float f) +{ + unsigned char val=(unsigned char)f; + short port = (short)x->x_port; + if(f<0. || f>255.) { + pd_error(x, "value %f out of bounds [0..255]", f); + return; + } + if(x->x_port<0. || x->x_port>NUM_DMXVALUES) { + pd_error(x, "port %f out of bounds [0..%d]", x->x_port, NUM_DMXVALUES); + return; + } + + dmxout_threaded_doout1(x, port, val); +} + +static void dmxout_threaded_list(t_dmxout_threaded*x, t_symbol*s, int argc, t_atom*argv) +{ + int count=(argcx_portrange)?argc:x->x_portrange; + int i=0; + int errors=0; + + int port=x->x_port; + if((port+count)>=NUM_DMXVALUES) { + if(count>NUM_DMXVALUES)count=NUM_DMXVALUES; + port=NUM_DMXVALUES-count; + } + + for(i=0; i255.) { + errors++; + if(f<0.)f=0.; + if(f>255)f=255; + } + g_values[port+i]=(unsigned char)f; + } + if(errors) { + pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); + } + + dmxout_threaded_doout(x); +} + +static void dmxout_threaded_port(t_dmxout_threaded*x, t_float f_baseport, t_floatarg f_portrange) +{ + short baseport =(short)f_baseport; + short portrange=(short)f_portrange; + + + if(baseport<0 || baseport>=NUM_DMXVALUES) { + pd_error(x, "port %f out of bounds [0..%d]", f_baseport, NUM_DMXVALUES); + baseport =0; + } + x->x_port = baseport; + + if(portrange<0) { + pd_error(x, "portrange %f<0! setting to 1", portrange); + portrange=1; + } else if (portrange==0) { + portrange=x->x_portrange; + } + + if (baseport+portrange>NUM_DMXVALUES) { + pd_error(x, "upper port exceeds %d! clamping", NUM_DMXVALUES); + portrange=NUM_DMXVALUES-baseport; + } + x->x_portrange=portrange; +} + +static void *dmxout_threaded_new(t_symbol*s, int argc, t_atom*argv) +{ + t_floatarg baseport=0.f, portrange=0.f; + t_dmxout_threaded *x = 0; + + switch(argc) { + case 2: + x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class2); + x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); + baseport=atom_getfloat(argv); + portrange=atom_getfloat(argv+1); + dmxout_threaded_port(x, baseport, portrange); + break; + case 1: + baseport=atom_getfloat(argv); + case 0: + x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class); + x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); + x->x_port = baseport; + x->x_portrange = -1; + break; + default: + return 0; + } + return (x); +} + +static void *dmxout_threaded_free(t_dmxout_threaded*x) +{ + // dmxout_threaded_close(); +} + +static void dmxout_threaded_init(void) { + int i=0; + g_thread_id=0; + g_mutex=NULL; + for(i=0; i Date: Wed, 2 Jul 2008 11:34:38 +0000 Subject: renamed: dmxout_threaded to dmxout and dmxout to dmxout_b (blocking) svn path=/trunk/externals/iem/dmx512/; revision=10133 --- dmx512/src/dmxout.c | 180 +++++++++++++++++--------- dmx512/src/dmxout_b.c | 240 ++++++++++++++++++++++++++++++++++ dmx512/src/dmxout_threaded.c | 302 ------------------------------------------- 3 files changed, 361 insertions(+), 361 deletions(-) create mode 100644 dmx512/src/dmxout_b.c delete mode 100644 dmx512/src/dmxout_threaded.c diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index 968110d..a35fb1b 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -1,6 +1,6 @@ /****************************************************** * - * dmxout - implementation file + * dmxout_threaded - implementation file * * copyleft (c) IOhannes m zmölnig * @@ -20,40 +20,84 @@ #include #include -static t_class *dmxout_class; -static t_class *dmxout_class2; +#include + + +static t_class *dmxout_threaded_class; +static t_class *dmxout_threaded_class2; #define NUM_DMXVALUES 512 -typedef struct _dmxout +static pthread_t g_thread_id; +static pthread_mutex_t *g_mutex; +static dmx_t g_values[NUM_DMXVALUES]; +static int g_device; +static int g_thread_running, g_thread_continue; + +typedef struct _dmxout_threaded { t_object x_obj; t_inlet *x_portinlet; - - int x_device; t_float x_port; int x_portrange; - dmx_t x_values[NUM_DMXVALUES]; -} t_dmxout; -static void dmxout_clearbuf(t_dmxout*x) +} t_dmxout_threaded; + + +static void *dmxout_threaded_thread(void*you) { - int i=0; - for(i=0; ix_values[i]=0; + pthread_mutex_t *mutex=g_mutex; + struct timeval timout; + + g_thread_running=1; + + while(g_thread_continue) { + timout.tv_sec = 0; + timout.tv_usec=100; + select(0,0,0,0,&timout); + + pthread_mutex_lock(g_mutex); + if(g_device>0) { + lseek (g_device, 0, SEEK_SET); /* set to the current channel */ + write (g_device, g_values, NUM_DMXVALUES); /* write the channel */ + } + pthread_mutex_unlock(g_mutex); + } + g_thread_running=0; + printf("quit thread"); + + return NULL; } -static void dmxout_close(t_dmxout*x) +static void dmxout_threaded_close() { - if(x->x_device>=0) { - close(x->x_device); + if(g_device>=0) { + close(g_device); + } + g_device=-1; + + if(g_thread_running) { + /* terminate the current thread! */ + void*dummy=0; + int counter=0; + g_thread_continue=0; + pthread_join(g_thread_id, &dummy); + while(g_thread_running) { + counter++; + } + } + g_thread_id=0; + if(g_mutex) { + pthread_mutex_destroy(g_mutex); + freebytes(g_mutex, sizeof(pthread_mutex_t)); + g_mutex=NULL; } - x->x_device=-1; } -static void dmxout_open(t_dmxout*x, t_symbol*s_devname) +static void dmxout_threaded_open(t_symbol*s_devname) { int argc=2; const char *args[2] = {"--dmx", s_devname->s_name}; @@ -61,51 +105,56 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) const char*devname=""; int fd; - dmxout_close(x); + dmxout_threaded_close(); if(s_devname && s_devname->s_name) devname=s_devname->s_name; // strncpy(args[0], "--dmx", MAXPDSTRING); // strncpy(args[1], devname, MAXPDSTRING); - verbose(2, "[dmxout]: trying to open '%s'", args[1]); + verbose(2, "[dmxout_threaded]: trying to open '%s'", args[1]); devname=DMXdev(&argc, argv); if(!devname){ - pd_error(x, "couldn't find DMX device"); + error("couldn't find DMX device"); return; } - verbose(1, "[dmxout] opening %s", devname); + verbose(1, "[dmxout_threaded] opening %s", devname); - fd = open (devname, O_WRONLY | O_NONBLOCK); + fd = open (devname, O_WRONLY); if(fd!=-1) { - x->x_device=fd; - dmxout_clearbuf(x); + g_device=fd; + + g_thread_running=0; + g_thread_continue=0; + g_mutex=(pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); + if ( pthread_mutex_init(g_mutex, NULL) < 0 ) { + error("couldn't create mutex"); + } else { + g_thread_continue = 1; + pthread_create(&g_thread_id, 0, dmxout_threaded_thread, NULL); + } } else { - pd_error(x, "failed to open DMX-device '%s'",devname); + error("failed to open DMX-device '%s'",devname); } } -static void dmxout_doout(t_dmxout*x) { - int device = x->x_device; - if(device<=0) { +static void dmxout_threaded_doout(t_dmxout_threaded*x) { + if(g_device<=0) { pd_error(x, "no DMX universe found"); return; } - - lseek (device, 0, SEEK_SET); /* set to the current channel */ - write (device, x->x_values, NUM_DMXVALUES); /* write the channel */ } -static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) +static void dmxout_threaded_doout1(t_dmxout_threaded*x, short port, unsigned char value) { - x->x_values[port]=value; - dmxout_doout(x); + g_values[port]=value; + dmxout_threaded_doout(x); } -static void dmxout_float(t_dmxout*x, t_float f) +static void dmxout_threaded_float(t_dmxout_threaded*x, t_float f) { unsigned char val=(unsigned char)f; short port = (short)x->x_port; @@ -118,10 +167,10 @@ static void dmxout_float(t_dmxout*x, t_float f) return; } - dmxout_doout1(x, port, val); + dmxout_threaded_doout1(x, port, val); } -static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) +static void dmxout_threaded_list(t_dmxout_threaded*x, t_symbol*s, int argc, t_atom*argv) { int count=(argcx_portrange)?argc:x->x_portrange; int i=0; @@ -140,16 +189,16 @@ static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) if(f<0.)f=0.; if(f>255)f=255; } - x->x_values[port+i]=(unsigned char)f; + g_values[port+i]=(unsigned char)f; } if(errors) { pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); } - dmxout_doout(x); + dmxout_threaded_doout(x); } -static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) +static void dmxout_threaded_port(t_dmxout_threaded*x, t_float f_baseport, t_floatarg f_portrange) { short baseport =(short)f_baseport; short portrange=(short)f_portrange; @@ -175,23 +224,23 @@ static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) x->x_portrange=portrange; } -static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) +static void *dmxout_threaded_new(t_symbol*s, int argc, t_atom*argv) { t_floatarg baseport=0.f, portrange=0.f; - t_dmxout *x = 0; + t_dmxout_threaded *x = 0; switch(argc) { case 2: - x=(t_dmxout *)pd_new(dmxout_class2); + x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class2); x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); baseport=atom_getfloat(argv); portrange=atom_getfloat(argv+1); - dmxout_port(x, baseport, portrange); + dmxout_threaded_port(x, baseport, portrange); break; case 1: baseport=atom_getfloat(argv); case 0: - x=(t_dmxout *)pd_new(dmxout_class); + x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class); x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); x->x_port = baseport; x->x_portrange = -1; @@ -199,42 +248,55 @@ static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) default: return 0; } - x->x_device=-1; - - dmxout_open(x, gensym("")); return (x); } -static void *dmxout_free(t_dmxout*x) +static void *dmxout_threaded_free(t_dmxout_threaded*x) { - dmxout_close(x); + // dmxout_threaded_close(); } +static void dmxout_threaded_init(void) { + int i=0; + g_thread_id=0; + g_mutex=NULL; + for(i=0; i +#include +#include + +static t_class *dmxout_class; +static t_class *dmxout_class2; + +#define NUM_DMXVALUES 512 + +typedef struct _dmxout +{ + t_object x_obj; + + t_inlet *x_portinlet; + + int x_device; + t_float x_port; + int x_portrange; + + dmx_t x_values[NUM_DMXVALUES]; +} t_dmxout; + +static void dmxout_clearbuf(t_dmxout*x) +{ + int i=0; + for(i=0; ix_values[i]=0; +} + +static void dmxout_close(t_dmxout*x) +{ + if(x->x_device>=0) { + close(x->x_device); + } + x->x_device=-1; +} + + +static void dmxout_open(t_dmxout*x, t_symbol*s_devname) +{ + int argc=2; + const char *args[2] = {"--dmx", s_devname->s_name}; + const char**argv=args; + const char*devname=""; + int fd; + + dmxout_close(x); + + if(s_devname && s_devname->s_name) + devname=s_devname->s_name; + + // strncpy(args[0], "--dmx", MAXPDSTRING); + // strncpy(args[1], devname, MAXPDSTRING); + verbose(2, "[dmxout]: trying to open '%s'", args[1]); + devname=DMXdev(&argc, argv); + if(!devname){ + pd_error(x, "couldn't find DMX device"); + return; + } + verbose(1, "[dmxout] opening %s", devname); + + fd = open (devname, O_WRONLY | O_NONBLOCK); + + if(fd!=-1) { + x->x_device=fd; + dmxout_clearbuf(x); + } else { + pd_error(x, "failed to open DMX-device '%s'",devname); + } +} + +static void dmxout_doout(t_dmxout*x) { + int device = x->x_device; + if(device<=0) { + pd_error(x, "no DMX universe found"); + return; + } + + lseek (device, 0, SEEK_SET); /* set to the current channel */ + write (device, x->x_values, NUM_DMXVALUES); /* write the channel */ +} + + +static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) +{ + x->x_values[port]=value; + dmxout_doout(x); +} + + +static void dmxout_float(t_dmxout*x, t_float f) +{ + unsigned char val=(unsigned char)f; + short port = (short)x->x_port; + if(f<0. || f>255.) { + pd_error(x, "value %f out of bounds [0..255]", f); + return; + } + if(x->x_port<0. || x->x_port>NUM_DMXVALUES) { + pd_error(x, "port %f out of bounds [0..%d]", x->x_port, NUM_DMXVALUES); + return; + } + + dmxout_doout1(x, port, val); +} + +static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) +{ + int count=(argcx_portrange)?argc:x->x_portrange; + int i=0; + int errors=0; + + int port=x->x_port; + if((port+count)>=NUM_DMXVALUES) { + if(count>NUM_DMXVALUES)count=NUM_DMXVALUES; + port=NUM_DMXVALUES-count; + } + + for(i=0; i255.) { + errors++; + if(f<0.)f=0.; + if(f>255)f=255; + } + x->x_values[port+i]=(unsigned char)f; + } + if(errors) { + pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); + } + + dmxout_doout(x); +} + +static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) +{ + short baseport =(short)f_baseport; + short portrange=(short)f_portrange; + + + if(baseport<0 || baseport>=NUM_DMXVALUES) { + pd_error(x, "port %f out of bounds [0..%d]", f_baseport, NUM_DMXVALUES); + baseport =0; + } + x->x_port = baseport; + + if(portrange<0) { + pd_error(x, "portrange %f<0! setting to 1", portrange); + portrange=1; + } else if (portrange==0) { + portrange=x->x_portrange; + } + + if (baseport+portrange>NUM_DMXVALUES) { + pd_error(x, "upper port exceeds %d! clamping", NUM_DMXVALUES); + portrange=NUM_DMXVALUES-baseport; + } + x->x_portrange=portrange; +} + +static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) +{ + t_floatarg baseport=0.f, portrange=0.f; + t_dmxout *x = 0; + + switch(argc) { + case 2: + x=(t_dmxout *)pd_new(dmxout_class2); + x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); + baseport=atom_getfloat(argv); + portrange=atom_getfloat(argv+1); + dmxout_port(x, baseport, portrange); + break; + case 1: + baseport=atom_getfloat(argv); + case 0: + x=(t_dmxout *)pd_new(dmxout_class); + x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); + x->x_port = baseport; + x->x_portrange = -1; + break; + default: + return 0; + } + x->x_device=-1; + + dmxout_open(x, gensym("")); + return (x); +} + +static void *dmxout_free(t_dmxout*x) +{ + dmxout_close(x); +} + + +void dmxout_setup(void) +{ +#ifdef DMX4PD_POSTBANNER + DMX4PD_POSTBANNER; +#endif + + dmxout_class = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, + sizeof(t_dmxout), + 0, + A_GIMME, A_NULL); + + class_addfloat(dmxout_class, dmxout_float); + class_addmethod(dmxout_class, (t_method)dmxout_open, gensym("open"), A_SYMBOL, A_NULL); + + dmxout_class2 = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, + sizeof(t_dmxout), + 0, + A_GIMME, A_NULL); + + class_addlist(dmxout_class2, dmxout_list); + + + class_addmethod(dmxout_class2, (t_method)dmxout_port, gensym("port"), + A_FLOAT, A_DEFFLOAT, A_NULL); + + class_addmethod(dmxout_class2, (t_method)dmxout_open, gensym("open"), A_SYMBOL, A_NULL); +} diff --git a/dmx512/src/dmxout_threaded.c b/dmx512/src/dmxout_threaded.c deleted file mode 100644 index a35fb1b..0000000 --- a/dmx512/src/dmxout_threaded.c +++ /dev/null @@ -1,302 +0,0 @@ -/****************************************************** - * - * dmxout_threaded - implementation file - * - * copyleft (c) IOhannes m zmölnig - * - * 0603:forum::für::umläute:2008 - * - * institute of electronic music and acoustics (iem) - * - ****************************************************** - * - * license: GNU General Public License v.2 - * - ******************************************************/ - -#include "dmx4pd.h" - -#include -#include -#include - -#include - - -static t_class *dmxout_threaded_class; -static t_class *dmxout_threaded_class2; - -#define NUM_DMXVALUES 512 - -static pthread_t g_thread_id; -static pthread_mutex_t *g_mutex; -static dmx_t g_values[NUM_DMXVALUES]; -static int g_device; -static int g_thread_running, g_thread_continue; - -typedef struct _dmxout_threaded -{ - t_object x_obj; - - t_inlet *x_portinlet; - t_float x_port; - int x_portrange; - - -} t_dmxout_threaded; - - -static void *dmxout_threaded_thread(void*you) -{ - pthread_mutex_t *mutex=g_mutex; - struct timeval timout; - - g_thread_running=1; - - while(g_thread_continue) { - timout.tv_sec = 0; - timout.tv_usec=100; - select(0,0,0,0,&timout); - - pthread_mutex_lock(g_mutex); - if(g_device>0) { - lseek (g_device, 0, SEEK_SET); /* set to the current channel */ - write (g_device, g_values, NUM_DMXVALUES); /* write the channel */ - } - pthread_mutex_unlock(g_mutex); - } - g_thread_running=0; - printf("quit thread"); - - return NULL; -} - -static void dmxout_threaded_close() -{ - if(g_device>=0) { - close(g_device); - } - g_device=-1; - - if(g_thread_running) { - /* terminate the current thread! */ - void*dummy=0; - int counter=0; - g_thread_continue=0; - pthread_join(g_thread_id, &dummy); - while(g_thread_running) { - counter++; - } - } - g_thread_id=0; - if(g_mutex) { - pthread_mutex_destroy(g_mutex); - freebytes(g_mutex, sizeof(pthread_mutex_t)); - g_mutex=NULL; - } -} - - -static void dmxout_threaded_open(t_symbol*s_devname) -{ - int argc=2; - const char *args[2] = {"--dmx", s_devname->s_name}; - const char**argv=args; - const char*devname=""; - int fd; - - dmxout_threaded_close(); - - if(s_devname && s_devname->s_name) - devname=s_devname->s_name; - - // strncpy(args[0], "--dmx", MAXPDSTRING); - // strncpy(args[1], devname, MAXPDSTRING); - verbose(2, "[dmxout_threaded]: trying to open '%s'", args[1]); - devname=DMXdev(&argc, argv); - if(!devname){ - error("couldn't find DMX device"); - return; - } - verbose(1, "[dmxout_threaded] opening %s", devname); - - fd = open (devname, O_WRONLY); - - if(fd!=-1) { - g_device=fd; - - g_thread_running=0; - g_thread_continue=0; - g_mutex=(pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); - if ( pthread_mutex_init(g_mutex, NULL) < 0 ) { - error("couldn't create mutex"); - } else { - g_thread_continue = 1; - pthread_create(&g_thread_id, 0, dmxout_threaded_thread, NULL); - } - } else { - error("failed to open DMX-device '%s'",devname); - } -} - -static void dmxout_threaded_doout(t_dmxout_threaded*x) { - if(g_device<=0) { - pd_error(x, "no DMX universe found"); - return; - } -} - - -static void dmxout_threaded_doout1(t_dmxout_threaded*x, short port, unsigned char value) -{ - g_values[port]=value; - dmxout_threaded_doout(x); -} - - -static void dmxout_threaded_float(t_dmxout_threaded*x, t_float f) -{ - unsigned char val=(unsigned char)f; - short port = (short)x->x_port; - if(f<0. || f>255.) { - pd_error(x, "value %f out of bounds [0..255]", f); - return; - } - if(x->x_port<0. || x->x_port>NUM_DMXVALUES) { - pd_error(x, "port %f out of bounds [0..%d]", x->x_port, NUM_DMXVALUES); - return; - } - - dmxout_threaded_doout1(x, port, val); -} - -static void dmxout_threaded_list(t_dmxout_threaded*x, t_symbol*s, int argc, t_atom*argv) -{ - int count=(argcx_portrange)?argc:x->x_portrange; - int i=0; - int errors=0; - - int port=x->x_port; - if((port+count)>=NUM_DMXVALUES) { - if(count>NUM_DMXVALUES)count=NUM_DMXVALUES; - port=NUM_DMXVALUES-count; - } - - for(i=0; i255.) { - errors++; - if(f<0.)f=0.; - if(f>255)f=255; - } - g_values[port+i]=(unsigned char)f; - } - if(errors) { - pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); - } - - dmxout_threaded_doout(x); -} - -static void dmxout_threaded_port(t_dmxout_threaded*x, t_float f_baseport, t_floatarg f_portrange) -{ - short baseport =(short)f_baseport; - short portrange=(short)f_portrange; - - - if(baseport<0 || baseport>=NUM_DMXVALUES) { - pd_error(x, "port %f out of bounds [0..%d]", f_baseport, NUM_DMXVALUES); - baseport =0; - } - x->x_port = baseport; - - if(portrange<0) { - pd_error(x, "portrange %f<0! setting to 1", portrange); - portrange=1; - } else if (portrange==0) { - portrange=x->x_portrange; - } - - if (baseport+portrange>NUM_DMXVALUES) { - pd_error(x, "upper port exceeds %d! clamping", NUM_DMXVALUES); - portrange=NUM_DMXVALUES-baseport; - } - x->x_portrange=portrange; -} - -static void *dmxout_threaded_new(t_symbol*s, int argc, t_atom*argv) -{ - t_floatarg baseport=0.f, portrange=0.f; - t_dmxout_threaded *x = 0; - - switch(argc) { - case 2: - x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class2); - x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); - baseport=atom_getfloat(argv); - portrange=atom_getfloat(argv+1); - dmxout_threaded_port(x, baseport, portrange); - break; - case 1: - baseport=atom_getfloat(argv); - case 0: - x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class); - x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); - x->x_port = baseport; - x->x_portrange = -1; - break; - default: - return 0; - } - return (x); -} - -static void *dmxout_threaded_free(t_dmxout_threaded*x) -{ - // dmxout_threaded_close(); -} - -static void dmxout_threaded_init(void) { - int i=0; - g_thread_id=0; - g_mutex=NULL; - for(i=0; i Date: Wed, 2 Jul 2008 11:40:32 +0000 Subject: made the threaded version the default; renamed the blocking version to [dmxout_b] svn path=/trunk/externals/iem/dmx512/; revision=10134 --- dmx512/src/dmxout.c | 79 ++++++++++++++++++++++++-------------------------- dmx512/src/dmxout_b.c | 80 +++++++++++++++++++++++++-------------------------- 2 files changed, 78 insertions(+), 81 deletions(-) diff --git a/dmx512/src/dmxout.c b/dmx512/src/dmxout.c index a35fb1b..18358ce 100644 --- a/dmx512/src/dmxout.c +++ b/dmx512/src/dmxout.c @@ -1,6 +1,6 @@ /****************************************************** * - * dmxout_threaded - implementation file + * dmxout - implementation file * * copyleft (c) IOhannes m zmölnig * @@ -23,8 +23,8 @@ #include -static t_class *dmxout_threaded_class; -static t_class *dmxout_threaded_class2; +static t_class *dmxout_class; +static t_class *dmxout_class2; #define NUM_DMXVALUES 512 @@ -34,7 +34,7 @@ static dmx_t g_values[NUM_DMXVALUES]; static int g_device; static int g_thread_running, g_thread_continue; -typedef struct _dmxout_threaded +typedef struct _dmxout { t_object x_obj; @@ -43,10 +43,10 @@ typedef struct _dmxout_threaded int x_portrange; -} t_dmxout_threaded; +} t_dmxout; -static void *dmxout_threaded_thread(void*you) +static void *dmxout_thread(void*you) { pthread_mutex_t *mutex=g_mutex; struct timeval timout; @@ -66,12 +66,11 @@ static void *dmxout_threaded_thread(void*you) pthread_mutex_unlock(g_mutex); } g_thread_running=0; - printf("quit thread"); return NULL; } -static void dmxout_threaded_close() +static void dmxout_close() { if(g_device>=0) { close(g_device); @@ -97,7 +96,7 @@ static void dmxout_threaded_close() } -static void dmxout_threaded_open(t_symbol*s_devname) +static void dmxout_open(t_symbol*s_devname) { int argc=2; const char *args[2] = {"--dmx", s_devname->s_name}; @@ -105,20 +104,20 @@ static void dmxout_threaded_open(t_symbol*s_devname) const char*devname=""; int fd; - dmxout_threaded_close(); + dmxout_close(); if(s_devname && s_devname->s_name) devname=s_devname->s_name; // strncpy(args[0], "--dmx", MAXPDSTRING); // strncpy(args[1], devname, MAXPDSTRING); - verbose(2, "[dmxout_threaded]: trying to open '%s'", args[1]); + verbose(2, "[dmxout]: trying to open '%s'", args[1]); devname=DMXdev(&argc, argv); if(!devname){ error("couldn't find DMX device"); return; } - verbose(1, "[dmxout_threaded] opening %s", devname); + verbose(1, "[dmxout] opening %s", devname); fd = open (devname, O_WRONLY); @@ -132,14 +131,14 @@ static void dmxout_threaded_open(t_symbol*s_devname) error("couldn't create mutex"); } else { g_thread_continue = 1; - pthread_create(&g_thread_id, 0, dmxout_threaded_thread, NULL); + pthread_create(&g_thread_id, 0, dmxout_thread, NULL); } } else { error("failed to open DMX-device '%s'",devname); } } -static void dmxout_threaded_doout(t_dmxout_threaded*x) { +static void dmxout_doout(t_dmxout*x) { if(g_device<=0) { pd_error(x, "no DMX universe found"); return; @@ -147,14 +146,14 @@ static void dmxout_threaded_doout(t_dmxout_threaded*x) { } -static void dmxout_threaded_doout1(t_dmxout_threaded*x, short port, unsigned char value) +static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) { g_values[port]=value; - dmxout_threaded_doout(x); + dmxout_doout(x); } -static void dmxout_threaded_float(t_dmxout_threaded*x, t_float f) +static void dmxout_float(t_dmxout*x, t_float f) { unsigned char val=(unsigned char)f; short port = (short)x->x_port; @@ -167,10 +166,10 @@ static void dmxout_threaded_float(t_dmxout_threaded*x, t_float f) return; } - dmxout_threaded_doout1(x, port, val); + dmxout_doout1(x, port, val); } -static void dmxout_threaded_list(t_dmxout_threaded*x, t_symbol*s, int argc, t_atom*argv) +static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) { int count=(argcx_portrange)?argc:x->x_portrange; int i=0; @@ -195,10 +194,10 @@ static void dmxout_threaded_list(t_dmxout_threaded*x, t_symbol*s, int argc, t_at pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); } - dmxout_threaded_doout(x); + dmxout_doout(x); } -static void dmxout_threaded_port(t_dmxout_threaded*x, t_float f_baseport, t_floatarg f_portrange) +static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) { short baseport =(short)f_baseport; short portrange=(short)f_portrange; @@ -224,23 +223,23 @@ static void dmxout_threaded_port(t_dmxout_threaded*x, t_float f_baseport, t_floa x->x_portrange=portrange; } -static void *dmxout_threaded_new(t_symbol*s, int argc, t_atom*argv) +static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) { t_floatarg baseport=0.f, portrange=0.f; - t_dmxout_threaded *x = 0; + t_dmxout *x = 0; switch(argc) { case 2: - x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class2); + x=(t_dmxout *)pd_new(dmxout_class2); x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); baseport=atom_getfloat(argv); portrange=atom_getfloat(argv+1); - dmxout_threaded_port(x, baseport, portrange); + dmxout_port(x, baseport, portrange); break; case 1: baseport=atom_getfloat(argv); case 0: - x=(t_dmxout_threaded *)pd_new(dmxout_threaded_class); + x=(t_dmxout *)pd_new(dmxout_class); x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); x->x_port = baseport; x->x_portrange = -1; @@ -251,12 +250,12 @@ static void *dmxout_threaded_new(t_symbol*s, int argc, t_atom*argv) return (x); } -static void *dmxout_threaded_free(t_dmxout_threaded*x) +static void *dmxout_free(t_dmxout*x) { - // dmxout_threaded_close(); + // dmxout_close(); } -static void dmxout_threaded_init(void) { +static void dmxout_init(void) { int i=0; g_thread_id=0; g_mutex=NULL; @@ -266,37 +265,35 @@ static void dmxout_threaded_init(void) { g_thread_running=0; g_thread_continue=0; - dmxout_threaded_open(gensym("")); - - post("running thread %d for device %d", g_thread_id, g_device); + dmxout_open(gensym("")); } -void dmxout_threaded_setup(void) +void dmxout_setup(void) { #ifdef DMX4PD_POSTBANNER DMX4PD_POSTBANNER; #endif - dmxout_threaded_class = class_new(gensym("dmxout_threaded"), (t_newmethod)dmxout_threaded_new, (t_method)dmxout_threaded_free, - sizeof(t_dmxout_threaded), + dmxout_class = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, + sizeof(t_dmxout), 0, A_GIMME, A_NULL); - class_addfloat(dmxout_threaded_class, dmxout_threaded_float); + class_addfloat(dmxout_class, dmxout_float); - dmxout_threaded_class2 = class_new(gensym("dmxout_threaded"), (t_newmethod)dmxout_threaded_new, (t_method)dmxout_threaded_free, - sizeof(t_dmxout_threaded), + dmxout_class2 = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, + sizeof(t_dmxout), 0, A_GIMME, A_NULL); - class_addlist(dmxout_threaded_class2, dmxout_threaded_list); + class_addlist(dmxout_class2, dmxout_list); - class_addmethod(dmxout_threaded_class2, (t_method)dmxout_threaded_port, gensym("port"), + class_addmethod(dmxout_class2, (t_method)dmxout_port, gensym("port"), A_FLOAT, A_DEFFLOAT, A_NULL); - dmxout_threaded_init(); + dmxout_init(); } diff --git a/dmx512/src/dmxout_b.c b/dmx512/src/dmxout_b.c index 968110d..9623397 100644 --- a/dmx512/src/dmxout_b.c +++ b/dmx512/src/dmxout_b.c @@ -1,6 +1,8 @@ /****************************************************** * - * dmxout - implementation file + * dmxout_b - implementation file + * + * this is the "blocking" version * * copyleft (c) IOhannes m zmölnig * @@ -20,12 +22,12 @@ #include #include -static t_class *dmxout_class; -static t_class *dmxout_class2; +static t_class *dmxout_b_class; +static t_class *dmxout_b_class2; #define NUM_DMXVALUES 512 -typedef struct _dmxout +typedef struct _dmxout_b { t_object x_obj; @@ -36,15 +38,15 @@ typedef struct _dmxout int x_portrange; dmx_t x_values[NUM_DMXVALUES]; -} t_dmxout; +} t_dmxout_b; -static void dmxout_clearbuf(t_dmxout*x) +static void dmxout_b_clearbuf(t_dmxout_b*x) { int i=0; for(i=0; ix_values[i]=0; } -static void dmxout_close(t_dmxout*x) +static void dmxout_b_close(t_dmxout_b*x) { if(x->x_device>=0) { close(x->x_device); @@ -53,7 +55,7 @@ static void dmxout_close(t_dmxout*x) } -static void dmxout_open(t_dmxout*x, t_symbol*s_devname) +static void dmxout_b_open(t_dmxout_b*x, t_symbol*s_devname) { int argc=2; const char *args[2] = {"--dmx", s_devname->s_name}; @@ -61,32 +63,30 @@ static void dmxout_open(t_dmxout*x, t_symbol*s_devname) const char*devname=""; int fd; - dmxout_close(x); + dmxout_b_close(x); if(s_devname && s_devname->s_name) devname=s_devname->s_name; - // strncpy(args[0], "--dmx", MAXPDSTRING); - // strncpy(args[1], devname, MAXPDSTRING); - verbose(2, "[dmxout]: trying to open '%s'", args[1]); + verbose(2, "[dmxout_b]: trying to open '%s'", args[1]); devname=DMXdev(&argc, argv); if(!devname){ pd_error(x, "couldn't find DMX device"); return; } - verbose(1, "[dmxout] opening %s", devname); + verbose(1, "[dmxout_b] opening %s", devname); fd = open (devname, O_WRONLY | O_NONBLOCK); if(fd!=-1) { x->x_device=fd; - dmxout_clearbuf(x); + dmxout_b_clearbuf(x); } else { pd_error(x, "failed to open DMX-device '%s'",devname); } } -static void dmxout_doout(t_dmxout*x) { +static void dmxout_b_doout(t_dmxout_b*x) { int device = x->x_device; if(device<=0) { pd_error(x, "no DMX universe found"); @@ -98,14 +98,14 @@ static void dmxout_doout(t_dmxout*x) { } -static void dmxout_doout1(t_dmxout*x, short port, unsigned char value) +static void dmxout_b_doout1(t_dmxout_b*x, short port, unsigned char value) { x->x_values[port]=value; - dmxout_doout(x); + dmxout_b_doout(x); } -static void dmxout_float(t_dmxout*x, t_float f) +static void dmxout_b_float(t_dmxout_b*x, t_float f) { unsigned char val=(unsigned char)f; short port = (short)x->x_port; @@ -118,10 +118,10 @@ static void dmxout_float(t_dmxout*x, t_float f) return; } - dmxout_doout1(x, port, val); + dmxout_b_doout1(x, port, val); } -static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) +static void dmxout_b_list(t_dmxout_b*x, t_symbol*s, int argc, t_atom*argv) { int count=(argcx_portrange)?argc:x->x_portrange; int i=0; @@ -146,10 +146,10 @@ static void dmxout_list(t_dmxout*x, t_symbol*s, int argc, t_atom*argv) pd_error(x, "%d valu%s out of bound [0..255]", errors, (1==errors)?"e":"es"); } - dmxout_doout(x); + dmxout_b_doout(x); } -static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) +static void dmxout_b_port(t_dmxout_b*x, t_float f_baseport, t_floatarg f_portrange) { short baseport =(short)f_baseport; short portrange=(short)f_portrange; @@ -175,23 +175,23 @@ static void dmxout_port(t_dmxout*x, t_float f_baseport, t_floatarg f_portrange) x->x_portrange=portrange; } -static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) +static void *dmxout_b_new(t_symbol*s, int argc, t_atom*argv) { t_floatarg baseport=0.f, portrange=0.f; - t_dmxout *x = 0; + t_dmxout_b *x = 0; switch(argc) { case 2: - x=(t_dmxout *)pd_new(dmxout_class2); + x=(t_dmxout_b *)pd_new(dmxout_b_class2); x->x_portinlet=inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("port")); baseport=atom_getfloat(argv); portrange=atom_getfloat(argv+1); - dmxout_port(x, baseport, portrange); + dmxout_b_port(x, baseport, portrange); break; case 1: baseport=atom_getfloat(argv); case 0: - x=(t_dmxout *)pd_new(dmxout_class); + x=(t_dmxout_b *)pd_new(dmxout_b_class); x->x_portinlet=floatinlet_new(&x->x_obj, &x->x_port); x->x_port = baseport; x->x_portrange = -1; @@ -201,40 +201,40 @@ static void *dmxout_new(t_symbol*s, int argc, t_atom*argv) } x->x_device=-1; - dmxout_open(x, gensym("")); + dmxout_b_open(x, gensym("")); return (x); } -static void *dmxout_free(t_dmxout*x) +static void *dmxout_b_free(t_dmxout_b*x) { - dmxout_close(x); + dmxout_b_close(x); } -void dmxout_setup(void) +void dmxout_b_setup(void) { #ifdef DMX4PD_POSTBANNER DMX4PD_POSTBANNER; #endif - dmxout_class = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, - sizeof(t_dmxout), + dmxout_b_class = class_new(gensym("dmxout_b"), (t_newmethod)dmxout_b_new, (t_method)dmxout_b_free, + sizeof(t_dmxout_b), 0, A_GIMME, A_NULL); - class_addfloat(dmxout_class, dmxout_float); - class_addmethod(dmxout_class, (t_method)dmxout_open, gensym("open"), A_SYMBOL, A_NULL); + class_addfloat(dmxout_b_class, dmxout_b_float); + class_addmethod(dmxout_b_class, (t_method)dmxout_b_open, gensym("open"), A_SYMBOL, A_NULL); - dmxout_class2 = class_new(gensym("dmxout"), (t_newmethod)dmxout_new, (t_method)dmxout_free, - sizeof(t_dmxout), + dmxout_b_class2 = class_new(gensym("dmxout_b"), (t_newmethod)dmxout_b_new, (t_method)dmxout_b_free, + sizeof(t_dmxout_b), 0, A_GIMME, A_NULL); - class_addlist(dmxout_class2, dmxout_list); + class_addlist(dmxout_b_class2, dmxout_b_list); - class_addmethod(dmxout_class2, (t_method)dmxout_port, gensym("port"), + class_addmethod(dmxout_b_class2, (t_method)dmxout_b_port, gensym("port"), A_FLOAT, A_DEFFLOAT, A_NULL); - class_addmethod(dmxout_class2, (t_method)dmxout_open, gensym("open"), A_SYMBOL, A_NULL); + class_addmethod(dmxout_b_class2, (t_method)dmxout_b_open, gensym("open"), A_SYMBOL, A_NULL); } -- cgit v1.2.1 From f584b800ba1069616625dfe34fdf68d0eafda672 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 16 Dec 2006 22:03:43 +0000 Subject: first stab at porting the Max aka.wiiremote object. it builds now, but I don't think it works svn path=/trunk/externals/io/; revision=6923 --- wiiremote/COPYRIGHT.txt | 13 ++ wiiremote/Makefile | 32 +++ wiiremote/aka.wiiremote.c | 362 +++++++++++++++++++++++++++++++ wiiremote/wiiremote.c | 543 ++++++++++++++++++++++++++++++++++++++++++++++ wiiremote/wiiremote.h | 62 ++++++ 5 files changed, 1012 insertions(+) create mode 100644 wiiremote/COPYRIGHT.txt create mode 100644 wiiremote/Makefile create mode 100644 wiiremote/aka.wiiremote.c create mode 100644 wiiremote/wiiremote.c create mode 100644 wiiremote/wiiremote.h diff --git a/wiiremote/COPYRIGHT.txt b/wiiremote/COPYRIGHT.txt new file mode 100644 index 0000000..b33233c --- /dev/null +++ b/wiiremote/COPYRIGHT.txt @@ -0,0 +1,13 @@ +Max porting by Masayuki Akamatsu +Copyright (c) 2006, Masayuki Akamatsu +Based on "DarwiinRemote" by Hiroaki Kimura +Copyright (c) 2006, Hiroaki Kimura +All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/wiiremote/Makefile b/wiiremote/Makefile new file mode 100644 index 0000000..78d1860 --- /dev/null +++ b/wiiremote/Makefile @@ -0,0 +1,32 @@ +TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') +EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') + +default: + make -C $(EXTERNALS_ROOT) $(TARGET) + +install: + make -C $(EXTERNALS_ROOT) $(TARGET)_install + +clean: + make -C $(EXTERNALS_ROOT) $(TARGET)_clean + +test_locations: + make -C $(EXTERNALS_ROOT) test_locations + +# for emacs +etags: + etags ../../../pd/src/*.h *.[ch] linux/input.h + make etags_`uname -s` + +etags_Darwin: + etags -a HID\ Utilities\ Source/*.[ch] \ + /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \ + /System/Library/Frameworks/Carbon.framework/Headers/*.h \ + /System/Library/Frameworks/IOKit.framework/Headers/hid*/*.[ch] + +etags_Linux: + etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: + etags -a /usr/include/*.h /usr/include/sys/*.h \ + /usr/local/include/*.h /usr/local/include/sys/*.h diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c new file mode 100644 index 0000000..4ec6ad0 --- /dev/null +++ b/wiiremote/aka.wiiremote.c @@ -0,0 +1,362 @@ +// aka.wiiremote.c +// Copyright by Masayuki Akamatsu +// port to Pd by Hans-Christoph Steiner + + +#ifdef PD +#include "m_pd.h" +#define SETLONG SETFLOAT +static t_class *wiiremote_class; +#else /* Max */ +#include "ext.h" +#endif +#include "wiiremote.h" + +#define kInterval 100 +#define kMaxTrial 100 + + +typedef struct _akawiiremote +{ +#ifdef PD + t_object x_obj; +#else /* Max */ + struct object obj; +#endif + + WiiRemoteRef wiiremote; + + void *clock; + long interval; + long trial; + + void *statusOut; + void *buttonsOut; + void *irOut; + void *accOut; +} t_akawiiremote; + +void *akawiiremote_class; // the number of instance of this object + +short akawiiremote_count; + +void akawiiremote_bang(t_akawiiremote *x); +void akawiiremote_connect(t_akawiiremote *x); +void akawiiremote_disconnect(t_akawiiremote *x); +void akawiiremote_motionsensor(t_akawiiremote *x, long enable); +void akawiiremote_irsensor(t_akawiiremote *x, long enable); +void akawiiremote_vibration(t_akawiiremote *x, long enable); +void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4); + +void akawiiremote_getbatterylevel(t_akawiiremote *x); +void akawiiremote_getexpansionstatus(t_akawiiremote *x); +void akawiiremote_getledstatus(t_akawiiremote *x); + +void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s); +void akawiiremote_clock(t_akawiiremote *x); +void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); +void akawiiremote_free(t_akawiiremote *x); + +#ifdef PD +void wiiremote_setup() +{ + wiiremote_class = class_new(gensym("wiiremote"), + (t_newmethod)akawiiremote_new, + (t_method)akawiiremote_free, + sizeof(t_akawiiremote), + CLASS_DEFAULT, + A_GIMME,0); + + class_addbang(wiiremote_class,(t_method)akawiiremote_bang); + class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); + + class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); + + post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); + post("\tPd port by Hans-Christoph Steiner"); + + akawiiremote_count = 0; +} +#else /* Max */ +void main() +{ + setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); + + addbang((method)akawiiremote_bang); + addmess((method)akawiiremote_connect,"connect",0); + addmess((method)akawiiremote_disconnect,"disconnect",0); + addmess((method)akawiiremote_motionsensor,"motionsensor", A_DEFLONG, 0); + addmess((method)akawiiremote_irsensor,"irsensor", A_DEFLONG, 0); + addmess((method)akawiiremote_vibration,"vibration", A_DEFLONG, 0); + addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); + + addmess((method)akawiiremote_getbatterylevel,"getbatterylevel",0); + addmess((method)akawiiremote_getexpansionstatus,"getexpansionstatus",0); + addmess((method)akawiiremote_getledstatus,"getledstatus",0); + + addmess((method)akawiiremote_assist,"assist",A_CANT,0); + + post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); + + akawiiremote_count = 0; +} +#endif /* PD */ +//-------------------------------------------------------------------------------------------- + +void akawiiremote_bang(t_akawiiremote *x) +{ + t_atom list[4]; + + if (x->wiiremote->device == nil) + return; // do nothing + +#ifdef PD + outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); + + if (x->wiiremote->isIRSensorEnabled) + { + SETFLOAT(list, x->wiiremote->posX); + SETFLOAT(list + 1, x->wiiremote->posY); + SETFLOAT(list + 2, x->wiiremote->angle); + SETFLOAT (list + 3, x->wiiremote->tracking); + outlet_list(x->irOut, &s_list, 4, list); + } + + if (x->wiiremote->isMotionSensorEnabled) + { + SETFLOAT(list, x->wiiremote->accX); + SETFLOAT(list + 1, x->wiiremote->accY); + SETFLOAT(list + 2, x->wiiremote->accZ); + SETFLOAT(list + 3, x->wiiremote->orientation); + outlet_list(x->accOut, &s_list, 4, list); + } +#else /* Max */ + outlet_int(x->buttonsOut, x->wiiremote->buttonData); + + if (x->wiiremote->isIRSensorEnabled) + { + SETFLOAT(list, x->wiiremote->posX); + SETFLOAT(list + 1, x->wiiremote->posY); + SETFLOAT(list + 2, x->wiiremote->angle); + SETLONG (list + 3, x->wiiremote->tracking); + outlet_list(x->irOut, 0L, 4, &list); + } + + if (x->wiiremote->isMotionSensorEnabled) + { + SETLONG(list, x->wiiremote->accX); + SETLONG(list + 1, x->wiiremote->accY); + SETLONG(list + 2, x->wiiremote->accZ); + SETLONG(list + 3, x->wiiremote->orientation); + outlet_list(x->accOut, 0L, 4, &list); + } +#endif /* PD */ + + wiiremote_getstatus(); +} + +void akawiiremote_connect(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) // if not connected + { + if (x->wiiremote->inquiry == nil) // if not seatching + { + Boolean result; + + result = wiiremote_search(); // start searching the device + x->trial = 0; + clock_delay(x->clock, 0); // start clock to check the device found + } + } + else // if already connected + { + t_atom status; + + SETLONG(&status, 1); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } +} + +void akawiiremote_disconnect(t_akawiiremote *x) +{ + Boolean result; + t_atom status; + + result = wiiremote_disconnect(); + SETLONG(&status, result); + outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); +} + +void akawiiremote_motionsensor(t_akawiiremote *x, long enable) +{ + wiiremote_motionsensor(enable); +} + +void akawiiremote_irsensor(t_akawiiremote *x, long enable) +{ + wiiremote_irsensor(enable); +} + +void akawiiremote_vibration(t_akawiiremote *x, long enable) +{ + wiiremote_vibration(enable); +} + +void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) +{ + wiiremote_led(enable1, enable2, enable3, enable4); +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_getbatterylevel(t_akawiiremote *x) +{ + t_atom status; + + SETFLOAT(&status, x->wiiremote->batteryLevel); + outlet_anything(x->statusOut, gensym("batterylevel"), 1, &status); +} + +void akawiiremote_getexpansionstatus(t_akawiiremote *x) +{ + t_atom status; + + SETLONG(&status, x->wiiremote->isExpansionPortUsed); + outlet_anything(x->statusOut, gensym("expansionstatus"), 1, &status); +} + +void akawiiremote_getledstatus(t_akawiiremote *x) +{ + t_atom list[4]; + + SETLONG(list, x->wiiremote->isLED1Illuminated); + SETLONG(list + 1, x->wiiremote->isLED2Illuminated); + SETLONG(list + 2, x->wiiremote->isLED3Illuminated); + SETLONG(list + 3, x->wiiremote->isLED4Illuminated); +#ifdef PD + outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); +#else /* Max */ + outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list); +#endif +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_clock(t_akawiiremote *x) +{ + Boolean result; + t_atom status; + + if (x->wiiremote->device != nil) // if the device is found... + { + clock_unset(x->clock); // stop clock + + wiiremote_stopsearch(); + result = wiiremote_connect(); // connect to it + SETLONG(&status, result); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } + else // if the device is not found... + { + x->trial++; + //SETLONG(&status, x->trial); + //outlet_anything(x->statusOut, gensym("searching"), 1, &status); + + if (x->trial >= kMaxTrial) // if trial is over + { + clock_unset(x->clock); // stop clock + + wiiremote_stopsearch(); + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } + else + { + //post("trial %d",x->trial); + clock_delay(x->clock, x->interval); // restart clock + } + } +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) +{ +#ifndef PD /* Max */ + if (m==ASSIST_INLET) + { + sprintf(s,"connect, bang, disconnect...."); + } + else +#endif /* NOT PD */ + { + switch(a) + { + case 0: sprintf(s,"list(acc-x acc-y acc-z orientation)"); break; + case 1: sprintf(s,"list(pos-x pos-y angle tracking)"); break; + case 2: sprintf(s,"int(buttons)"); break; + case 3: sprintf(s,"message(status)"); break; + } + } +} + +//-------------------------------------------------------------------------------------------- + +void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) +{ +#ifdef PD + t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + + x->clock = clock_new(x, (t_method)akawiiremote_clock); + + /* create anything outlet used for HID data */ + x->statusOut = outlet_new(&x->x_obj, 0); + x->buttonsOut = outlet_new(&x->x_obj, &s_float); + x->irOut = outlet_new(&x->x_obj, &s_list); + x->accOut = outlet_new(&x->x_obj, &s_list); +#else /* Max */ + t_akawiiremote *x; + + x = (t_akawiiremote *)newobject(akawiiremote_class); + + x->wiiremote = wiiremote_init(); + + x->clock = clock_new(x, (method)akawiiremote_clock); + + x->statusOut = outlet_new(x, 0); + x->buttonsOut = intout(x); + x->irOut = listout(x); + x->accOut = listout(x); +#endif /* PD */ + x->trial = 0; + x->interval = kInterval; + + + akawiiremote_count++; + return x; +} + +void akawiiremote_free(t_akawiiremote *x) +{ + akawiiremote_count--; + if (akawiiremote_count == 0) + wiiremote_disconnect(); + +#ifdef PD + if (x->clock) + clock_unset(x->clock); + clock_free(x->clock); +#else /* Max */ + freeobject(x->clock); +#endif +} + diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c new file mode 100644 index 0000000..13b1ea6 --- /dev/null +++ b/wiiremote/wiiremote.c @@ -0,0 +1,543 @@ +// wiiremote.c +// Copyright by Masayuki Akamatsu +// Based on "DarwiinRemote" by Hiroaki Kimura + +#include "wiiremote.h" + +// this type is used a lot (data array): +typedef unsigned char darr[]; + +#define kTrial 10 + +static WiiRemoteRec gWiiRemote; + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +WiiRemoteRef wiiremote_init(void) +{ + gWiiRemote.inquiry = nil; + gWiiRemote.device = nil; + gWiiRemote.ichan = nil; + gWiiRemote.cchan = nil; + + gWiiRemote.accX = 0x10; + gWiiRemote.accY = 0x10; + gWiiRemote.accZ = 0x10; + gWiiRemote.buttonData = 0; + gWiiRemote.leftPoint = -1; + gWiiRemote.tracking = false; + + gWiiRemote.batteryLevel = 0; + + gWiiRemote.isIRSensorEnabled = false; + gWiiRemote.isMotionSensorEnabled = false; + gWiiRemote.isVibrationEnabled = false; + + gWiiRemote.isExpansionPortUsed = false; + gWiiRemote.isLED1Illuminated = false; + gWiiRemote.isLED2Illuminated = false; + gWiiRemote.isLED3Illuminated = false; + gWiiRemote.isLED4Illuminated = false; + + return &gWiiRemote; +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +void checkDevice(IOBluetoothDeviceRef device) +{ + CFStringRef myString; + + myString = IOBluetoothDeviceGetName(device); + if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + { + gWiiRemote.device = IOBluetoothObjectRetain(device); + } +} + +IOBluetoothDeviceInquiryDeviceFoundCallback myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) +{ + checkDevice(device); +} + +IOBluetoothDeviceInquiryDeviceNameUpdatedCallback myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) +{ + checkDevice(device); +} + +IOBluetoothDeviceInquiryCompleteCallback myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) +{ + IOReturn result; + + if (aborted) return; // called by stop ;) + + if (error != kIOReturnSuccess) + { + wiiremote_stopsearch(); + return; + } +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_search(void) +{ + IOReturn ret; + + if (gWiiRemote.inquiry != nil) + return true; + + gWiiRemote.inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon(nil); + IOBluetoothDeviceInquirySetDeviceFoundCallback(gWiiRemote.inquiry, myFoundFunc); + IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(gWiiRemote.inquiry, myUpdatedFunc); + IOBluetoothDeviceInquirySetCompleteCallback(gWiiRemote.inquiry, myCompleteFunc); + + ret = IOBluetoothDeviceInquiryStart(gWiiRemote.inquiry); + if (ret != kIOReturnSuccess) + { + IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry); + gWiiRemote.inquiry = nil; + return false; + } + return true; +} + +Boolean wiiremote_stopsearch(void) +{ + IOReturn ret; + + if (gWiiRemote.inquiry == nil) + { + return true; // already stopped + } + + ret = IOBluetoothDeviceInquiryStop(gWiiRemote.inquiry); + + if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted) + { + // kIOReturnNotPermitted is if it's already stopped + } + + IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry); + gWiiRemote.inquiry = nil; + + return (ret==kIOReturnSuccess); +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + + IOBluetoothL2CAPChannelIncomingDataListener myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) +{ + unsigned char *dp = (unsigned char*)data; + + if (dp[1] == 0x20 && length >= 8) + { + gWiiRemote.batteryLevel = (double)dp[7]; + gWiiRemote.batteryLevel /= (double)0xC0; + + gWiiRemote.isExpansionPortUsed = (dp[4] & 0x02) != 0; + gWiiRemote.isLED1Illuminated = (dp[4] & 0x10) != 0; + gWiiRemote.isLED2Illuminated = (dp[4] & 0x20) != 0; + gWiiRemote.isLED3Illuminated = (dp[4] & 0x40) != 0; + gWiiRemote.isLED4Illuminated = (dp[4] & 0x80) != 0; + + //have to reset settings (vibration, motion, IR and so on...) + wiiremote_irsensor(gWiiRemote.isIRSensorEnabled); + } + + if ((dp[1]&0xF0) == 0x30) + { + gWiiRemote.buttonData = ((short)dp[2] << 8) + dp[3]; + + if (dp[1] & 0x01) + { + gWiiRemote.accX = dp[4]; + gWiiRemote.accY = dp[5]; + gWiiRemote.accZ = dp[6]; + + gWiiRemote.lowZ = gWiiRemote.lowZ * .9 + gWiiRemote.accZ * .1; + gWiiRemote.lowX = gWiiRemote.lowX * .9 + gWiiRemote.accX * .1; + + float absx = abs(gWiiRemote.lowX - 128); + float absz = abs(gWiiRemote.lowZ - 128); + + if (gWiiRemote.orientation == 0 || gWiiRemote.orientation == 2) absx -= 5; + if (gWiiRemote.orientation == 1 || gWiiRemote.orientation == 3) absz -= 5; + + if (absz >= absx) + { + if (absz > 5) + gWiiRemote.orientation = (gWiiRemote.lowZ > 128) ? 0 : 2; + } + else + { + if (absx > 5) + gWiiRemote.orientation = (gWiiRemote.lowX > 128) ? 3 : 1; + } + //printf("orientation: %d\n", orientation); + } + + if (dp[1] & 0x02) + { + int i; + for(i=0 ; i<4 ; i++) + { + gWiiRemote.irData[i].x = dp[7 + 3*i]; + gWiiRemote.irData[i].y = dp[8 + 3*i]; + gWiiRemote.irData[i].s = dp[9 + 3*i]; + gWiiRemote.irData[i].x += (gWiiRemote.irData[i].s & 0x30) << 4; + gWiiRemote.irData[i].y += (gWiiRemote.irData[i].s & 0xC0) << 2; + gWiiRemote.irData[i].s &= 0x0F; + } + } + } + + float ox, oy; + + if (gWiiRemote.irData[0].s < 0x0F && gWiiRemote.irData[1].s < 0x0F) + { + int l = gWiiRemote.leftPoint, r; + if (gWiiRemote.leftPoint == -1) + { + // printf("Tracking.\n"); + switch (gWiiRemote.orientation) + { + case 0: l = (gWiiRemote.irData[0].x < gWiiRemote.irData[1].x) ? 0 : 1; break; + case 1: l = (gWiiRemote.irData[0].y > gWiiRemote.irData[1].y) ? 0 : 1; break; + case 2: l = (gWiiRemote.irData[0].x > gWiiRemote.irData[1].x) ? 0 : 1; break; + case 3: l = (gWiiRemote.irData[0].y < gWiiRemote.irData[1].y) ? 0 : 1; break; + } + gWiiRemote.leftPoint = l; + } + + r = 1-l; + + float dx = gWiiRemote.irData[r].x - gWiiRemote.irData[l].x; + float dy = gWiiRemote.irData[r].y - gWiiRemote.irData[l].y; + + float d = sqrt(dx*dx+dy*dy); + + dx /= d; + dy /= d; + + float cx = (gWiiRemote.irData[l].x+gWiiRemote.irData[r].x)/1024.0 - 1; + float cy = (gWiiRemote.irData[l].y+gWiiRemote.irData[r].y)/1024.0 - .75; + + gWiiRemote.angle = atan2(dy, dx); + + ox = -dy*cy-dx*cx; + oy = -dx*cy+dy*cx; + //printf("x:%5.2f; y: %5.2f; angle: %5.1f\n", ox, oy, angle*180/M_PI); + + gWiiRemote.tracking = true; + } + else + { + // printf("Not tracking.\n"); + ox = oy = -100; + gWiiRemote.leftPoint = -1; + gWiiRemote.tracking = false; + } + + gWiiRemote.posX = ox; + gWiiRemote.posY = oy; +} + +IOBluetoothL2CAPChannelIncomingEventListener myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) +{ + switch (event->eventType) + { + case kIOBluetoothL2CAPChannelEventTypeData: + // In thise case: + // event->u.newData.dataPtr is a pointer to the block of data received. + // event->u.newData.dataSize is the size of the block of data. + myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); + break; + + case kIOBluetoothL2CAPChannelEventTypeClosed: + // In this case: + // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel + // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). + break; + } +} + +IOBluetoothUserNotificationCallback myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) +{ + wiiremote_disconnect(); +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_connect(void) +{ + IOReturn result; + short i; + + if (gWiiRemote.device == nil) + return false; + + // connect the device + for (i=0; i>24) & 0xFF; + cmd[2] = (address>>16) & 0xFF; + cmd[3] = (address>> 8) & 0xFF; + cmd[4] = (address>> 0) & 0xFF; + cmd[5] = length; + + // and of course the vibration flag, as usual + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + + data = cmd; + + return sendCommand(cmd, 22); +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_motionsensor(Boolean enabled) +{ + gWiiRemote.isMotionSensorEnabled = enabled; + + unsigned char cmd[] = {0x12, 0x00, 0x30}; + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (gWiiRemote.isMotionSensorEnabled) cmd[2] |= 0x01; + if (gWiiRemote.isIRSensorEnabled) cmd[2] |= 0x02; + + return sendCommand(cmd, 3); +} + +Boolean wiiremote_irsensor(Boolean enabled) +{ + IOReturn ret; + + gWiiRemote.isIRSensorEnabled = enabled; + + // set register 0x12 (report type) + if (ret = wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled)) return ret; + + // set register 0x13 (ir enable/vibe) + if (ret = wiiremote_vibration(gWiiRemote.isVibrationEnabled)) return ret; + + // set register 0x1a (ir enable 2) + unsigned char cmd[] = {0x1a, 0x00}; + if (enabled) cmd[1] |= 0x04; + if (ret = sendCommand(cmd, 2)) return ret; + + if(enabled){ + // based on marcan's method, found on wiili wiki: + // tweaked to include some aspects of cliff's setup procedure in the hopes + // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) + // the sleeps help it it seems + usleep(10000); + if (ret = writeData((darr){0x01}, 0x04B00030, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x90}, 0x04B00006, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0xC0}, 0x04B00008, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x40}, 0x04B0001A, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x33}, 0x04B00033, 1)) return ret; + usleep(10000); + if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret; + + }else{ + // probably should do some writes to power down the camera, save battery + // but don't know how yet. + + //bug fix #1614587 + wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled); + wiiremote_vibration(gWiiRemote.isVibrationEnabled); + } + + return true; +} + +Boolean wiiremote_vibration(Boolean enabled) +{ + + gWiiRemote.isVibrationEnabled = enabled; + + unsigned char cmd[] = {0x13, 0x00}; + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (gWiiRemote.isIRSensorEnabled) cmd[1] |= 0x04; + + return sendCommand(cmd, 2);; +} + +Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) +{ + unsigned char cmd[] = {0x11, 0x00}; + if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (enabled1) cmd[1] |= 0x10; + if (enabled2) cmd[1] |= 0x20; + if (enabled3) cmd[1] |= 0x40; + if (enabled4) cmd[1] |= 0x80; + + gWiiRemote.isLED1Illuminated = enabled1; + gWiiRemote.isLED2Illuminated = enabled2; + gWiiRemote.isLED3Illuminated = enabled3; + gWiiRemote.isLED4Illuminated = enabled4; + + return sendCommand(cmd, 2); +} + +void wiiremote_getstatus(void) +{ + unsigned char cmd[] = {0x15, 0x00}; + sendCommand(cmd, 2); +} + + diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h new file mode 100644 index 0000000..1e8cb00 --- /dev/null +++ b/wiiremote/wiiremote.h @@ -0,0 +1,62 @@ +// wiiremote.h +// Copyright by Masayuki Akamatsu +// Based on "DarwiinRemote" by Hiroaki Kimura + +#include +#include +#include + +#include +#include + +typedef struct { + int x, y, s; +} IRData; + +typedef struct _WiiRemoteRec +{ + IOBluetoothDeviceInquiryRef inquiry; + IOBluetoothDeviceRef device; + IOBluetoothL2CAPChannelRef ichan; + IOBluetoothL2CAPChannelRef cchan; + + unsigned char accX; + unsigned char accY; + unsigned char accZ; + unsigned short buttonData; + + float lowZ; + float lowX; + int orientation; + int leftPoint; // is point 0 or 1 on the left. -1 when not tracking. + float posX; + float posY; + float angle; + Boolean tracking; + + IRData irData[4]; + double batteryLevel; + + Boolean isIRSensorEnabled; + Boolean isMotionSensorEnabled; + Boolean isVibrationEnabled; + + Boolean isExpansionPortUsed; + Boolean isLED1Illuminated; + Boolean isLED2Illuminated; + Boolean isLED3Illuminated; + Boolean isLED4Illuminated; + + IOBluetoothUserNotificationCallback *disconnectNotification; +} WiiRemoteRec, *WiiRemoteRef; + +WiiRemoteRef wiiremote_init(void); +Boolean wiiremote_search(void); +Boolean wiiremote_stopsearch(void); +Boolean wiiremote_connect(void); +Boolean wiiremote_disconnect(void); +Boolean wiiremote_motionsensor(Boolean enabled); +Boolean wiiremote_irsensor(Boolean enabled); +Boolean wiiremote_vibration(Boolean enabled); +Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); +void wiiremote_getstatus(void); -- cgit v1.2.1 From 110c6fbdaac1a56dddb6c978eb7a89c195758286 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 16 Dec 2006 22:25:22 +0000 Subject: cleaned things up a bit (less compiler warnings) and added to the auto-build as part of the 'io' libdir svn path=/trunk/externals/io/; revision=6925 --- wiiremote/aka.wiiremote.c | 10 +++++++--- wiiremote/wiiremote.c | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 4ec6ad0..6ad24d9 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -238,13 +238,17 @@ void akawiiremote_getledstatus(t_akawiiremote *x) { t_atom list[4]; +#ifdef PD + SETFLOAT(list, x->wiiremote->isLED1Illuminated); + SETFLOAT(list + 1, x->wiiremote->isLED2Illuminated); + SETFLOAT(list + 2, x->wiiremote->isLED3Illuminated); + SETFLOAT(list + 3, x->wiiremote->isLED4Illuminated); + outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); +#else /* Max */ SETLONG(list, x->wiiremote->isLED1Illuminated); SETLONG(list + 1, x->wiiremote->isLED2Illuminated); SETLONG(list + 2, x->wiiremote->isLED3Illuminated); SETLONG(list + 3, x->wiiremote->isLED4Illuminated); -#ifdef PD - outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); -#else /* Max */ outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list); #endif } diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c index 13b1ea6..35acd03 100644 --- a/wiiremote/wiiremote.c +++ b/wiiremote/wiiremote.c @@ -4,6 +4,8 @@ #include "wiiremote.h" +#include + // this type is used a lot (data array): typedef unsigned char darr[]; -- cgit v1.2.1 From 9a6afb879b41110e8ae58cdb2898a6c3a6e3ad3f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 17 Dec 2006 16:56:21 +0000 Subject: fixed crasher, I forgot to include init in the Pd end of things svn path=/trunk/externals/io/; revision=6928 --- wiiremote/aka.wiiremote.c | 9 +++++++-- wiiremote/wiiremote-help.pd | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 wiiremote/wiiremote-help.pd diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 6ad24d9..89e6248 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -115,9 +115,12 @@ void main() void akawiiremote_bang(t_akawiiremote *x) { t_atom list[4]; - - if (x->wiiremote->device == nil) + + if (x->wiiremote->device == nil) + { + post("warning: your WiiRemote is not connected"); return; // do nothing + } #ifdef PD outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); @@ -319,6 +322,8 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) { #ifdef PD t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + + x->wiiremote = wiiremote_init(); x->clock = clock_new(x, (t_method)akawiiremote_clock); diff --git a/wiiremote/wiiremote-help.pd b/wiiremote/wiiremote-help.pd new file mode 100644 index 0000000..b3faed8 --- /dev/null +++ b/wiiremote/wiiremote-help.pd @@ -0,0 +1,30 @@ +#N canvas 41 171 573 456 10; +#X obj 451 21 import io; +#X obj 169 251 wiiremote; +#X msg 124 70 connect; +#X msg 141 96 disconnect; +#X msg 242 100 motionsensor \$1; +#X obj 242 78 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X obj 362 78 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 362 100 irsensor \$1; +#X obj 20 117 metro 100; +#X obj 20 96 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +; +#X msg 332 153 getbatterylevel; +#X msg 332 173 getledstatus; +#X msg 332 193 getexpansionstatus; +#X msg 85 146 bang; +#X connect 2 0 1 0; +#X connect 3 0 1 0; +#X connect 4 0 1 0; +#X connect 5 0 4 0; +#X connect 6 0 7 0; +#X connect 7 0 1 0; +#X connect 8 0 1 0; +#X connect 9 0 8 0; +#X connect 10 0 1 0; +#X connect 11 0 1 0; +#X connect 12 0 1 0; +#X connect 13 0 1 0; -- cgit v1.2.1 From 19cc31e3fd6942030173981be17ed88ef860ef88 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 28 Dec 2006 22:57:22 +0000 Subject: ported b3 from Masayuki Akamatsu, looks complete now svn path=/trunk/externals/io/; revision=7091 --- wiiremote/Makefile | 7 ++- wiiremote/README.txt | 6 ++ wiiremote/aka.wiiremote.c | 148 +++++++++++++++++++++------------------------- wiiremote/wiiremote.c | 78 ++++++++++++++---------- wiiremote/wiiremote.h | 3 +- 5 files changed, 128 insertions(+), 114 deletions(-) create mode 100644 wiiremote/README.txt diff --git a/wiiremote/Makefile b/wiiremote/Makefile index 78d1860..e222c9b 100644 --- a/wiiremote/Makefile +++ b/wiiremote/Makefile @@ -15,14 +15,15 @@ test_locations: # for emacs etags: - etags ../../../pd/src/*.h *.[ch] linux/input.h + etags ../../../pd/src/*.h *.[ch] make etags_`uname -s` etags_Darwin: - etags -a HID\ Utilities\ Source/*.[ch] \ + etags -a \ /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \ + /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \ /System/Library/Frameworks/Carbon.framework/Headers/*.h \ - /System/Library/Frameworks/IOKit.framework/Headers/hid*/*.[ch] + /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[ch] etags_Linux: etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h diff --git a/wiiremote/README.txt b/wiiremote/README.txt new file mode 100644 index 0000000..bdaf778 --- /dev/null +++ b/wiiremote/README.txt @@ -0,0 +1,6 @@ + +This is a port of the Max class aka.wiiremote by Masayuki Akamatsu. Its +available here: + +http://www.iamas.ac.jp/~aka/max/#aka_wiiremote + diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 89e6248..3c09341 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -1,7 +1,8 @@ // aka.wiiremote.c // Copyright by Masayuki Akamatsu -// port to Pd by Hans-Christoph Steiner - +// 1.0B1 : 2006.12.12 +// 1.0B2 : 2006.12.15 +// 1.0B3 : 2006.12.20 #ifdef PD #include "m_pd.h" @@ -9,13 +10,15 @@ static t_class *wiiremote_class; #else /* Max */ #include "ext.h" -#endif +#endif /* PD */ + #include "wiiremote.h" +#include + #define kInterval 100 #define kMaxTrial 100 - typedef struct _akawiiremote { #ifdef PD @@ -29,7 +32,7 @@ typedef struct _akawiiremote void *clock; long interval; long trial; - + void *statusOut; void *buttonsOut; void *irOut; @@ -59,7 +62,32 @@ void akawiiremote_free(t_akawiiremote *x); #ifdef PD void wiiremote_setup() +#else /* Max */ +void main() +#endif /* PD */ { + NumVersion outSoftwareVersion; + BluetoothHCIVersionInfo outHardwareVersion; + + if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) + { + if (outSoftwareVersion.majorRev < 1 || outSoftwareVersion.minorAndBugRev < 0x63) + { + error("requires Blutooth version 1.6.3 or later."); + return; + } + } + else + { + error("can't get Bluetooth version."); + return; + } + + post("aka.wiiremote 1.0B3-UB by Masayuki Akamatsu"); + +#ifdef PD + post("\tPd port by Hans-Christoph Steiner"); + wiiremote_class = class_new(gensym("wiiremote"), (t_newmethod)akawiiremote_new, (t_method)akawiiremote_free, @@ -80,15 +108,7 @@ void wiiremote_setup() class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); - - post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); - post("\tPd port by Hans-Christoph Steiner"); - - akawiiremote_count = 0; -} #else /* Max */ -void main() -{ setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); addbang((method)akawiiremote_bang); @@ -104,46 +124,25 @@ void main() addmess((method)akawiiremote_getledstatus,"getledstatus",0); addmess((method)akawiiremote_assist,"assist",A_CANT,0); - - post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); +#endif /* PD */ akawiiremote_count = 0; } -#endif /* PD */ + //-------------------------------------------------------------------------------------------- void akawiiremote_bang(t_akawiiremote *x) { t_atom list[4]; - - if (x->wiiremote->device == nil) - { - post("warning: your WiiRemote is not connected"); + + if (x->wiiremote->device == nil) return; // do nothing - } - + #ifdef PD outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); - - if (x->wiiremote->isIRSensorEnabled) - { - SETFLOAT(list, x->wiiremote->posX); - SETFLOAT(list + 1, x->wiiremote->posY); - SETFLOAT(list + 2, x->wiiremote->angle); - SETFLOAT (list + 3, x->wiiremote->tracking); - outlet_list(x->irOut, &s_list, 4, list); - } - - if (x->wiiremote->isMotionSensorEnabled) - { - SETFLOAT(list, x->wiiremote->accX); - SETFLOAT(list + 1, x->wiiremote->accY); - SETFLOAT(list + 2, x->wiiremote->accZ); - SETFLOAT(list + 3, x->wiiremote->orientation); - outlet_list(x->accOut, &s_list, 4, list); - } #else /* Max */ outlet_int(x->buttonsOut, x->wiiremote->buttonData); +#endif /* PD */ if (x->wiiremote->isIRSensorEnabled) { @@ -151,7 +150,7 @@ void akawiiremote_bang(t_akawiiremote *x) SETFLOAT(list + 1, x->wiiremote->posY); SETFLOAT(list + 2, x->wiiremote->angle); SETLONG (list + 3, x->wiiremote->tracking); - outlet_list(x->irOut, 0L, 4, &list); + outlet_list(x->irOut, 0L, 4, list); } if (x->wiiremote->isMotionSensorEnabled) @@ -160,35 +159,35 @@ void akawiiremote_bang(t_akawiiremote *x) SETLONG(list + 1, x->wiiremote->accY); SETLONG(list + 2, x->wiiremote->accZ); SETLONG(list + 3, x->wiiremote->orientation); - outlet_list(x->accOut, 0L, 4, &list); + outlet_list(x->accOut, 0L, 4, list); } -#endif /* PD */ - wiiremote_getstatus(); + //wiiremote_getstatus(); // stopped in B3 } void akawiiremote_connect(t_akawiiremote *x) { - if (x->wiiremote->device == nil) // if not connected - { - if (x->wiiremote->inquiry == nil) // if not seatching - { - Boolean result; + t_atom status; + Boolean result; - result = wiiremote_search(); // start searching the device - x->trial = 0; - clock_delay(x->clock, 0); // start clock to check the device found - } + if (wiiremote_isconnected()) + { + SETLONG(&status, -1); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); } - else // if already connected + else { - t_atom status; - - SETLONG(&status, 1); - outlet_anything(x->statusOut, gensym("connect"), 1, &status); + result = wiiremote_search(); // start searching the device + x->trial = 0; + clock_unset(x->clock); // stop clock + clock_delay(x->clock, 0); // start clock to check the device found } } +void akawiiremote_foundFunc(t_akawiiremote *x) +{ +} + void akawiiremote_disconnect(t_akawiiremote *x) { Boolean result; @@ -241,19 +240,11 @@ void akawiiremote_getledstatus(t_akawiiremote *x) { t_atom list[4]; -#ifdef PD - SETFLOAT(list, x->wiiremote->isLED1Illuminated); - SETFLOAT(list + 1, x->wiiremote->isLED2Illuminated); - SETFLOAT(list + 2, x->wiiremote->isLED3Illuminated); - SETFLOAT(list + 3, x->wiiremote->isLED4Illuminated); - outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); -#else /* Max */ SETLONG(list, x->wiiremote->isLED1Illuminated); SETLONG(list + 1, x->wiiremote->isLED2Illuminated); SETLONG(list + 2, x->wiiremote->isLED3Illuminated); SETLONG(list + 3, x->wiiremote->isLED4Illuminated); - outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list); -#endif + outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); } //-------------------------------------------------------------------------------------------- @@ -263,16 +254,17 @@ void akawiiremote_clock(t_akawiiremote *x) Boolean result; t_atom status; - if (x->wiiremote->device != nil) // if the device is found... + if (wiiremote_isconnected()) // if the device is connected... { clock_unset(x->clock); // stop clock wiiremote_stopsearch(); - result = wiiremote_connect(); // connect to it - SETLONG(&status, result); + //result = wiiremote_connect(); // remove in B3 + wiiremote_getstatus(); // add in B3 + SETLONG(&status, 1); outlet_anything(x->statusOut, gensym("connect"), 1, &status); } - else // if the device is not found... + else // if the device is not connected... { x->trial++; //SETLONG(&status, x->trial); @@ -334,13 +326,13 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) x->accOut = outlet_new(&x->x_obj, &s_list); #else /* Max */ t_akawiiremote *x; - + x = (t_akawiiremote *)newobject(akawiiremote_class); x->wiiremote = wiiremote_init(); x->clock = clock_new(x, (method)akawiiremote_clock); - + x->statusOut = outlet_new(x, 0); x->buttonsOut = intout(x); x->irOut = listout(x); @@ -348,7 +340,6 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) #endif /* PD */ x->trial = 0; x->interval = kInterval; - akawiiremote_count++; return x; @@ -359,13 +350,12 @@ void akawiiremote_free(t_akawiiremote *x) akawiiremote_count--; if (akawiiremote_count == 0) wiiremote_disconnect(); - + + clock_unset(x->clock); #ifdef PD - if (x->clock) - clock_unset(x->clock); clock_free(x->clock); #else /* Max */ - freeobject(x->clock); -#endif + freeobject((t_object *)x->clock); +#endif /* PD */ } diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c index 35acd03..b379f5e 100644 --- a/wiiremote/wiiremote.c +++ b/wiiremote/wiiremote.c @@ -3,7 +3,6 @@ // Based on "DarwiinRemote" by Hiroaki Kimura #include "wiiremote.h" - #include // this type is used a lot (data array): @@ -53,37 +52,47 @@ void checkDevice(IOBluetoothDeviceRef device) CFStringRef myString; myString = IOBluetoothDeviceGetName(device); - if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + if (myString != nil) { - gWiiRemote.device = IOBluetoothObjectRetain(device); + if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + { + gWiiRemote.device = IOBluetoothObjectRetain(device); + if ( !wiiremote_connect()) // add in B3 + wiiremote_disconnect(); // add in B3 + } } } -IOBluetoothDeviceInquiryDeviceFoundCallback myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) +void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) { checkDevice(device); } -IOBluetoothDeviceInquiryDeviceNameUpdatedCallback myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) +void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) { checkDevice(device); } -IOBluetoothDeviceInquiryCompleteCallback myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) +void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) { - IOReturn result; - if (aborted) return; // called by stop ;) if (error != kIOReturnSuccess) { wiiremote_stopsearch(); - return; } } //-------------------------------------------------------------------------------------------- +Boolean wiiremote_isconnected(void) +{ + Boolean result; + + result = gWiiRemote.device != nil && IOBluetoothDeviceIsConnected(gWiiRemote.device); + return result; +} + Boolean wiiremote_search(void) { IOReturn ret; @@ -131,7 +140,7 @@ Boolean wiiremote_stopsearch(void) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- - IOBluetoothL2CAPChannelIncomingDataListener myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) + void myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) { unsigned char *dp = (unsigned char*)data; @@ -248,35 +257,33 @@ Boolean wiiremote_stopsearch(void) gWiiRemote.posY = oy; } -IOBluetoothL2CAPChannelIncomingEventListener myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) +void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) { - switch (event->eventType) + if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) { - case kIOBluetoothL2CAPChannelEventTypeData: - // In thise case: - // event->u.newData.dataPtr is a pointer to the block of data received. - // event->u.newData.dataSize is the size of the block of data. - myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); - break; - - case kIOBluetoothL2CAPChannelEventTypeClosed: - // In this case: - // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel - // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). - break; + // In thise case: + // event->u.newData.dataPtr is a pointer to the block of data received. + // event->u.newData.dataSize is the size of the block of data. + myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); + } + else + if (event->eventType == kIOBluetoothL2CAPChannelEventTypeClosed) + { + // In this case: + // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel + // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). } } -IOBluetoothUserNotificationCallback myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) +void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) { - wiiremote_disconnect(); + //wiiremote_disconnect(); } //-------------------------------------------------------------------------------------------- Boolean wiiremote_connect(void) { - IOReturn result; short i; if (gWiiRemote.device == nil) @@ -289,7 +296,8 @@ Boolean wiiremote_connect(void) break; usleep(10000); // wait 10ms } - if (i==kTrial) return false; + if (i==kTrial) + return false; gWiiRemote.disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(gWiiRemote.device, myDisconnectedFunc, 0); @@ -300,7 +308,8 @@ Boolean wiiremote_connect(void) break; usleep(10000); // wait 10ms } - if (i==kTrial) return false; + if (i==kTrial) + return false; // open L2CAPChannel : BluetoothL2CAPPSM = 17 for (i=0; i Date: Thu, 28 Dec 2006 23:16:03 +0000 Subject: ported b4 from Masayuki Akamatsu, fixed one minor warning svn path=/trunk/externals/io/; revision=7092 --- wiiremote/aka.wiiremote.c | 47 ++--- wiiremote/aka.wiiremote_b2_pd-port.patch | 223 ++++++++++++++++++++ wiiremote/aka.wiiremote_b3_pd-port.patch | 176 ++++++++++++++++ wiiremote/aka.wiiremote_b4_pd-port.patch | 186 ++++++++++++++++ wiiremote/wiiremote.c | 351 ++++++++++++++++--------------- wiiremote/wiiremote.h | 23 +- 6 files changed, 797 insertions(+), 209 deletions(-) create mode 100644 wiiremote/aka.wiiremote_b2_pd-port.patch create mode 100644 wiiremote/aka.wiiremote_b3_pd-port.patch create mode 100644 wiiremote/aka.wiiremote_b4_pd-port.patch diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 3c09341..662f94e 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -13,7 +13,6 @@ static t_class *wiiremote_class; #endif /* PD */ #include "wiiremote.h" - #include #define kInterval 100 @@ -41,8 +40,6 @@ typedef struct _akawiiremote void *akawiiremote_class; // the number of instance of this object -short akawiiremote_count; - void akawiiremote_bang(t_akawiiremote *x); void akawiiremote_connect(t_akawiiremote *x); void akawiiremote_disconnect(t_akawiiremote *x); @@ -83,7 +80,7 @@ void main() return; } - post("aka.wiiremote 1.0B3-UB by Masayuki Akamatsu"); + post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); #ifdef PD post("\tPd port by Hans-Christoph Steiner"); @@ -125,8 +122,6 @@ void main() addmess((method)akawiiremote_assist,"assist",A_CANT,0); #endif /* PD */ - - akawiiremote_count = 0; } //-------------------------------------------------------------------------------------------- @@ -170,14 +165,14 @@ void akawiiremote_connect(t_akawiiremote *x) t_atom status; Boolean result; - if (wiiremote_isconnected()) + if (wiiremote_isconnected(x->wiiremote)) { SETLONG(&status, -1); outlet_anything(x->statusOut, gensym("connect"), 1, &status); } else { - result = wiiremote_search(); // start searching the device + result = wiiremote_search(x->wiiremote); // start searching the device x->trial = 0; clock_unset(x->clock); // stop clock clock_delay(x->clock, 0); // start clock to check the device found @@ -193,29 +188,29 @@ void akawiiremote_disconnect(t_akawiiremote *x) Boolean result; t_atom status; - result = wiiremote_disconnect(); + result = wiiremote_disconnect(x->wiiremote); SETLONG(&status, result); outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); } void akawiiremote_motionsensor(t_akawiiremote *x, long enable) { - wiiremote_motionsensor(enable); + wiiremote_motionsensor(x->wiiremote, enable); } void akawiiremote_irsensor(t_akawiiremote *x, long enable) { - wiiremote_irsensor(enable); + wiiremote_irsensor(x->wiiremote, enable); } void akawiiremote_vibration(t_akawiiremote *x, long enable) { - wiiremote_vibration(enable); + wiiremote_vibration(x->wiiremote, enable); } void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) { - wiiremote_led(enable1, enable2, enable3, enable4); + wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); } //-------------------------------------------------------------------------------------------- @@ -251,16 +246,16 @@ void akawiiremote_getledstatus(t_akawiiremote *x) void akawiiremote_clock(t_akawiiremote *x) { - Boolean result; + //Boolean result; t_atom status; - if (wiiremote_isconnected()) // if the device is connected... + if (wiiremote_isconnected(x->wiiremote)) // if the device is connected... { clock_unset(x->clock); // stop clock - wiiremote_stopsearch(); + wiiremote_stopsearch(x->wiiremote); //result = wiiremote_connect(); // remove in B3 - wiiremote_getstatus(); // add in B3 + wiiremote_getstatus(x->wiiremote); // add in B3 SETLONG(&status, 1); outlet_anything(x->statusOut, gensym("connect"), 1, &status); } @@ -274,7 +269,7 @@ void akawiiremote_clock(t_akawiiremote *x) { clock_unset(x->clock); // stop clock - wiiremote_stopsearch(); + wiiremote_stopsearch(x->wiiremote); SETLONG(&status, 0); outlet_anything(x->statusOut, gensym("connect"), 1, &status); } @@ -315,7 +310,8 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) #ifdef PD t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); - x->wiiremote = wiiremote_init(); + if (x->wiiremote != nil) + wiiremote_init(x->wiiremote); x->clock = clock_new(x, (t_method)akawiiremote_clock); @@ -329,7 +325,9 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) x = (t_akawiiremote *)newobject(akawiiremote_class); - x->wiiremote = wiiremote_init(); + x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); // add in 1.0B4 + if (x->wiiremote != nil) + wiiremote_init(x->wiiremote); x->clock = clock_new(x, (method)akawiiremote_clock); @@ -341,15 +339,16 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) x->trial = 0; x->interval = kInterval; - akawiiremote_count++; return x; } void akawiiremote_free(t_akawiiremote *x) { - akawiiremote_count--; - if (akawiiremote_count == 0) - wiiremote_disconnect(); + if (x->wiiremote != nil) // add in 1.0B4 + { + wiiremote_disconnect(x->wiiremote); + freebytes(x->wiiremote, sizeof(WiiRemoteRec)); // add in 1.0B4 + } clock_unset(x->clock); #ifdef PD diff --git a/wiiremote/aka.wiiremote_b2_pd-port.patch b/wiiremote/aka.wiiremote_b2_pd-port.patch new file mode 100644 index 0000000..3f96112 --- /dev/null +++ b/wiiremote/aka.wiiremote_b2_pd-port.patch @@ -0,0 +1,223 @@ +--- /Users/hans/Desktop/aka.wiiremote-b2-src/aka.wiiremote.c 2006-12-15 08:36:06.000000000 -0500 ++++ aka.wiiremote.c 2006-12-16 17:05:31.000000000 -0500 +@@ -1,15 +1,28 @@ + // aka.wiiremote.c + // Copyright by Masayuki Akamatsu ++// port to Pd by Hans-Christoph Steiner + ++ ++#ifdef PD ++#include "m_pd.h" ++#define SETLONG SETFLOAT ++static t_class *wiiremote_class; ++#else /* Max */ + #include "ext.h" ++#endif + #include "wiiremote.h" + + #define kInterval 100 + #define kMaxTrial 100 + ++ + typedef struct _akawiiremote + { ++#ifdef PD ++ t_object x_obj; ++#else /* Max */ + struct object obj; ++#endif + + WiiRemoteRef wiiremote; + +@@ -44,6 +57,36 @@ + void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); + void akawiiremote_free(t_akawiiremote *x); + ++#ifdef PD ++void wiiremote_setup() ++{ ++ wiiremote_class = class_new(gensym("wiiremote"), ++ (t_newmethod)akawiiremote_new, ++ (t_method)akawiiremote_free, ++ sizeof(t_akawiiremote), ++ CLASS_DEFAULT, ++ A_GIMME,0); ++ ++ class_addbang(wiiremote_class,(t_method)akawiiremote_bang); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); ++ ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); ++ ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); ++ ++ post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); ++ post("\tPd port by Hans-Christoph Steiner"); ++ ++ akawiiremote_count = 0; ++} ++#else /* Max */ + void main() + { + setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); +@@ -66,7 +109,7 @@ + + akawiiremote_count = 0; + } +- ++#endif /* PD */ + //-------------------------------------------------------------------------------------------- + + void akawiiremote_bang(t_akawiiremote *x) +@@ -76,6 +119,27 @@ + if (x->wiiremote->device == nil) + return; // do nothing + ++#ifdef PD ++ outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); ++ ++ if (x->wiiremote->isIRSensorEnabled) ++ { ++ SETFLOAT(list, x->wiiremote->posX); ++ SETFLOAT(list + 1, x->wiiremote->posY); ++ SETFLOAT(list + 2, x->wiiremote->angle); ++ SETFLOAT (list + 3, x->wiiremote->tracking); ++ outlet_list(x->irOut, &s_list, 4, list); ++ } ++ ++ if (x->wiiremote->isMotionSensorEnabled) ++ { ++ SETFLOAT(list, x->wiiremote->accX); ++ SETFLOAT(list + 1, x->wiiremote->accY); ++ SETFLOAT(list + 2, x->wiiremote->accZ); ++ SETFLOAT(list + 3, x->wiiremote->orientation); ++ outlet_list(x->accOut, &s_list, 4, list); ++ } ++#else /* Max */ + outlet_int(x->buttonsOut, x->wiiremote->buttonData); + + if (x->wiiremote->isIRSensorEnabled) +@@ -95,6 +159,7 @@ + SETLONG(list + 3, x->wiiremote->orientation); + outlet_list(x->accOut, 0L, 4, &list); + } ++#endif /* PD */ + + wiiremote_getstatus(); + } +@@ -173,11 +238,19 @@ + { + t_atom list[4]; + ++#ifdef PD ++ SETFLOAT(list, x->wiiremote->isLED1Illuminated); ++ SETFLOAT(list + 1, x->wiiremote->isLED2Illuminated); ++ SETFLOAT(list + 2, x->wiiremote->isLED3Illuminated); ++ SETFLOAT(list + 3, x->wiiremote->isLED4Illuminated); ++ outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); ++#else /* Max */ + SETLONG(list, x->wiiremote->isLED1Illuminated); + SETLONG(list + 1, x->wiiremote->isLED2Illuminated); + SETLONG(list + 2, x->wiiremote->isLED3Illuminated); + SETLONG(list + 3, x->wiiremote->isLED4Illuminated); + outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list); ++#endif + } + + //-------------------------------------------------------------------------------------------- +@@ -222,11 +295,13 @@ + + void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) + { ++#ifndef PD /* Max */ + if (m==ASSIST_INLET) + { + sprintf(s,"connect, bang, disconnect...."); + } + else ++#endif /* NOT PD */ + { + switch(a) + { +@@ -242,6 +317,17 @@ + + void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) + { ++#ifdef PD ++ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); ++ ++ x->clock = clock_new(x, (t_method)akawiiremote_clock); ++ ++ /* create anything outlet used for HID data */ ++ x->statusOut = outlet_new(&x->x_obj, 0); ++ x->buttonsOut = outlet_new(&x->x_obj, &s_float); ++ x->irOut = outlet_new(&x->x_obj, &s_list); ++ x->accOut = outlet_new(&x->x_obj, &s_list); ++#else /* Max */ + t_akawiiremote *x; + + x = (t_akawiiremote *)newobject(akawiiremote_class); +@@ -249,13 +335,15 @@ + x->wiiremote = wiiremote_init(); + + x->clock = clock_new(x, (method)akawiiremote_clock); +- x->trial = 0; +- x->interval = kInterval; + + x->statusOut = outlet_new(x, 0); + x->buttonsOut = intout(x); + x->irOut = listout(x); + x->accOut = listout(x); ++#endif /* PD */ ++ x->trial = 0; ++ x->interval = kInterval; ++ + + akawiiremote_count++; + return x; +@@ -267,6 +355,12 @@ + if (akawiiremote_count == 0) + wiiremote_disconnect(); + ++#ifdef PD ++ if (x->clock) ++ clock_unset(x->clock); ++ clock_free(x->clock); ++#else /* Max */ + freeobject(x->clock); ++#endif + } + +--- /Users/hans/Desktop/aka.wiiremote-b2-src/wiiremote.h 2006-12-14 10:21:42.000000000 -0500 ++++ wiiremote.h 2006-12-16 16:48:38.000000000 -0500 +@@ -2,9 +2,13 @@ + // Copyright by Masayuki Akamatsu + // Based on "DarwiinRemote" by Hiroaki Kimura + ++#include + #include + #include + ++#include ++#include ++ + typedef struct { + int x, y, s; + } IRData; +--- /Users/hans/Desktop/aka.wiiremote-b2-src/wiiremote.c 2006-12-15 08:31:05.000000000 -0500 ++++ wiiremote.c 2006-12-16 17:12:14.000000000 -0500 +@@ -4,6 +4,8 @@ + + #include "wiiremote.h" + ++#include ++ + // this type is used a lot (data array): + typedef unsigned char darr[]; + diff --git a/wiiremote/aka.wiiremote_b3_pd-port.patch b/wiiremote/aka.wiiremote_b3_pd-port.patch new file mode 100644 index 0000000..8609c62 --- /dev/null +++ b/wiiremote/aka.wiiremote_b3_pd-port.patch @@ -0,0 +1,176 @@ +--- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b3-src/wiiremote.h 2006-12-20 05:29:31.000000000 -0500 ++++ wiiremote.h 2006-12-28 01:36:00.000000000 -0500 +@@ -2,8 +2,13 @@ + // Copyright by Masayuki Akamatsu + // Based on "DarwiinRemote" by Hiroaki Kimura + ++#include ++#include + #include + ++#include ++#include ++ + typedef struct { + int x, y, s; + } IRData; +--- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b3-src/aka.wiiremote.c 2006-12-20 06:09:10.000000000 -0500 ++++ aka.wiiremote.c 2006-12-28 17:47:08.000000000 -0500 +@@ -4,15 +4,28 @@ + // 1.0B2 : 2006.12.15 + // 1.0B3 : 2006.12.20 + ++#ifdef PD ++#include "m_pd.h" ++#define SETLONG SETFLOAT ++static t_class *wiiremote_class; ++#else /* Max */ + #include "ext.h" ++#endif /* PD */ ++ + #include "wiiremote.h" + ++#include ++ + #define kInterval 100 + #define kMaxTrial 100 + + typedef struct _akawiiremote + { ++#ifdef PD ++ t_object x_obj; ++#else /* Max */ + struct object obj; ++#endif + + WiiRemoteRef wiiremote; + +@@ -47,7 +60,11 @@ + void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); + void akawiiremote_free(t_akawiiremote *x); + ++#ifdef PD ++void wiiremote_setup() ++#else /* Max */ + void main() ++#endif /* PD */ + { + NumVersion outSoftwareVersion; + BluetoothHCIVersionInfo outHardwareVersion; +@@ -66,6 +83,32 @@ + return; + } + ++ post("aka.wiiremote 1.0B3-UB by Masayuki Akamatsu"); ++ ++#ifdef PD ++ post("\tPd port by Hans-Christoph Steiner"); ++ ++ wiiremote_class = class_new(gensym("wiiremote"), ++ (t_newmethod)akawiiremote_new, ++ (t_method)akawiiremote_free, ++ sizeof(t_akawiiremote), ++ CLASS_DEFAULT, ++ A_GIMME,0); ++ ++ class_addbang(wiiremote_class,(t_method)akawiiremote_bang); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); ++ ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); ++ ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); ++#else /* Max */ + setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); + + addbang((method)akawiiremote_bang); +@@ -81,8 +124,7 @@ + addmess((method)akawiiremote_getledstatus,"getledstatus",0); + + addmess((method)akawiiremote_assist,"assist",A_CANT,0); +- +- post("aka.wiiremote 1.0B3-UB by Masayuki Akamatsu"); ++#endif /* PD */ + + akawiiremote_count = 0; + } +@@ -96,7 +138,11 @@ + if (x->wiiremote->device == nil) + return; // do nothing + ++#ifdef PD ++ outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); ++#else /* Max */ + outlet_int(x->buttonsOut, x->wiiremote->buttonData); ++#endif /* PD */ + + if (x->wiiremote->isIRSensorEnabled) + { +@@ -244,11 +290,13 @@ + + void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) + { ++#ifndef PD /* Max */ + if (m==ASSIST_INLET) + { + sprintf(s,"connect, bang, disconnect...."); + } + else ++#endif /* NOT PD */ + { + switch(a) + { +@@ -264,6 +312,19 @@ + + void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) + { ++#ifdef PD ++ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); ++ ++ x->wiiremote = wiiremote_init(); ++ ++ x->clock = clock_new(x, (t_method)akawiiremote_clock); ++ ++ /* create anything outlet used for HID data */ ++ x->statusOut = outlet_new(&x->x_obj, 0); ++ x->buttonsOut = outlet_new(&x->x_obj, &s_float); ++ x->irOut = outlet_new(&x->x_obj, &s_list); ++ x->accOut = outlet_new(&x->x_obj, &s_list); ++#else /* Max */ + t_akawiiremote *x; + + x = (t_akawiiremote *)newobject(akawiiremote_class); +@@ -271,13 +332,14 @@ + x->wiiremote = wiiremote_init(); + + x->clock = clock_new(x, (method)akawiiremote_clock); +- x->trial = 0; +- x->interval = kInterval; + + x->statusOut = outlet_new(x, 0); + x->buttonsOut = intout(x); + x->irOut = listout(x); + x->accOut = listout(x); ++#endif /* PD */ ++ x->trial = 0; ++ x->interval = kInterval; + + akawiiremote_count++; + return x; +@@ -290,6 +352,10 @@ + wiiremote_disconnect(); + + clock_unset(x->clock); ++#ifdef PD ++ clock_free(x->clock); ++#else /* Max */ + freeobject((t_object *)x->clock); ++#endif /* PD */ + } + diff --git a/wiiremote/aka.wiiremote_b4_pd-port.patch b/wiiremote/aka.wiiremote_b4_pd-port.patch new file mode 100644 index 0000000..0edf592 --- /dev/null +++ b/wiiremote/aka.wiiremote_b4_pd-port.patch @@ -0,0 +1,186 @@ +--- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b4-src/wiiremote.c 2006-12-23 09:52:07.000000000 -0500 ++++ wiiremote.c 2006-12-28 18:11:52.000000000 -0500 +@@ -444,7 +444,7 @@ + Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, size_t length) + { + unsigned char cmd[22]; +- int i; ++ unsigned int i; + + for(i=0 ; i ++#include + #include ++#include ++#include + + typedef struct { + int x, y, s; +--- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b4-src/aka.wiiremote.c 2006-12-22 19:18:31.000000000 -0500 ++++ aka.wiiremote.c 2006-12-28 18:09:23.000000000 -0500 +@@ -4,15 +4,27 @@ + // 1.0B2 : 2006.12.15 + // 1.0B3 : 2006.12.20 + ++#ifdef PD ++#include "m_pd.h" ++#define SETLONG SETFLOAT ++static t_class *wiiremote_class; ++#else /* Max */ + #include "ext.h" ++#endif /* PD */ ++ + #include "wiiremote.h" ++#include + + #define kInterval 100 + #define kMaxTrial 100 + + typedef struct _akawiiremote + { ++#ifdef PD ++ t_object x_obj; ++#else /* Max */ + struct object obj; ++#endif + + WiiRemoteRef wiiremote; + +@@ -45,7 +57,11 @@ + void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); + void akawiiremote_free(t_akawiiremote *x); + ++#ifdef PD ++void wiiremote_setup() ++#else /* Max */ + void main() ++#endif /* PD */ + { + NumVersion outSoftwareVersion; + BluetoothHCIVersionInfo outHardwareVersion; +@@ -64,6 +80,32 @@ + return; + } + ++ post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); ++ ++#ifdef PD ++ post("\tPd port by Hans-Christoph Steiner"); ++ ++ wiiremote_class = class_new(gensym("wiiremote"), ++ (t_newmethod)akawiiremote_new, ++ (t_method)akawiiremote_free, ++ sizeof(t_akawiiremote), ++ CLASS_DEFAULT, ++ A_GIMME,0); ++ ++ class_addbang(wiiremote_class,(t_method)akawiiremote_bang); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); ++ ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); ++ ++ class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); ++#else /* Max */ + setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); + + addbang((method)akawiiremote_bang); +@@ -79,9 +121,7 @@ + addmess((method)akawiiremote_getledstatus,"getledstatus",0); + + addmess((method)akawiiremote_assist,"assist",A_CANT,0); +- +- post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); +- ++#endif /* PD */ + } + + //-------------------------------------------------------------------------------------------- +@@ -93,7 +133,11 @@ + if (x->wiiremote->device == nil) + return; // do nothing + ++#ifdef PD ++ outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); ++#else /* Max */ + outlet_int(x->buttonsOut, x->wiiremote->buttonData); ++#endif /* PD */ + + if (x->wiiremote->isIRSensorEnabled) + { +@@ -241,11 +285,13 @@ + + void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) + { ++#ifndef PD /* Max */ + if (m==ASSIST_INLET) + { + sprintf(s,"connect, bang, disconnect...."); + } + else ++#endif /* NOT PD */ + { + switch(a) + { +@@ -261,6 +307,20 @@ + + void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) + { ++#ifdef PD ++ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); ++ ++ if (x->wiiremote != nil) ++ wiiremote_init(x->wiiremote); ++ ++ x->clock = clock_new(x, (t_method)akawiiremote_clock); ++ ++ /* create anything outlet used for HID data */ ++ x->statusOut = outlet_new(&x->x_obj, 0); ++ x->buttonsOut = outlet_new(&x->x_obj, &s_float); ++ x->irOut = outlet_new(&x->x_obj, &s_list); ++ x->accOut = outlet_new(&x->x_obj, &s_list); ++#else /* Max */ + t_akawiiremote *x; + + x = (t_akawiiremote *)newobject(akawiiremote_class); +@@ -270,13 +330,14 @@ + wiiremote_init(x->wiiremote); + + x->clock = clock_new(x, (method)akawiiremote_clock); +- x->trial = 0; +- x->interval = kInterval; + + x->statusOut = outlet_new(x, 0); + x->buttonsOut = intout(x); + x->irOut = listout(x); + x->accOut = listout(x); ++#endif /* PD */ ++ x->trial = 0; ++ x->interval = kInterval; + + return x; + } +@@ -290,6 +351,10 @@ + } + + clock_unset(x->clock); ++#ifdef PD ++ clock_free(x->clock); ++#else /* Max */ + freeobject((t_object *)x->clock); ++#endif /* PD */ + } + diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c index b379f5e..cabbb6e 100644 --- a/wiiremote/wiiremote.c +++ b/wiiremote/wiiremote.c @@ -10,44 +10,42 @@ typedef unsigned char darr[]; #define kTrial 10 -static WiiRemoteRec gWiiRemote; +//static WiiRemoteRec gWiiRemote; // remove in 1.0B4 //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -WiiRemoteRef wiiremote_init(void) +void wiiremote_init(WiiRemoteRef wiiremote) { - gWiiRemote.inquiry = nil; - gWiiRemote.device = nil; - gWiiRemote.ichan = nil; - gWiiRemote.cchan = nil; - - gWiiRemote.accX = 0x10; - gWiiRemote.accY = 0x10; - gWiiRemote.accZ = 0x10; - gWiiRemote.buttonData = 0; - gWiiRemote.leftPoint = -1; - gWiiRemote.tracking = false; - - gWiiRemote.batteryLevel = 0; - - gWiiRemote.isIRSensorEnabled = false; - gWiiRemote.isMotionSensorEnabled = false; - gWiiRemote.isVibrationEnabled = false; - - gWiiRemote.isExpansionPortUsed = false; - gWiiRemote.isLED1Illuminated = false; - gWiiRemote.isLED2Illuminated = false; - gWiiRemote.isLED3Illuminated = false; - gWiiRemote.isLED4Illuminated = false; - - return &gWiiRemote; + wiiremote->inquiry = nil; + wiiremote->device = nil; + wiiremote->ichan = nil; + wiiremote->cchan = nil; + + wiiremote->accX = 0x10; + wiiremote->accY = 0x10; + wiiremote->accZ = 0x10; + wiiremote->buttonData = 0; + wiiremote->leftPoint = -1; + wiiremote->tracking = false; + + wiiremote->batteryLevel = 0; + + wiiremote->isIRSensorEnabled = false; + wiiremote->isMotionSensorEnabled = false; + wiiremote->isVibrationEnabled = false; + + wiiremote->isExpansionPortUsed = false; + wiiremote->isLED1Illuminated = false; + wiiremote->isLED2Illuminated = false; + wiiremote->isLED3Illuminated = false; + wiiremote->isLED4Illuminated = false; } //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -void checkDevice(IOBluetoothDeviceRef device) +void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) { CFStringRef myString; @@ -56,21 +54,21 @@ void checkDevice(IOBluetoothDeviceRef device) { if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) { - gWiiRemote.device = IOBluetoothObjectRetain(device); - if ( !wiiremote_connect()) // add in B3 - wiiremote_disconnect(); // add in B3 + wiiremote->device = IOBluetoothObjectRetain(device); + if ( !wiiremote_connect(wiiremote)) // add in B3 + wiiremote_disconnect(wiiremote); // add in B3 } } } void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) { - checkDevice(device); + checkDevice((WiiRemoteRef)refCon, device); } void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) { - checkDevice(device); + checkDevice((WiiRemoteRef)refCon, device); } void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) @@ -79,60 +77,60 @@ void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn if (error != kIOReturnSuccess) { - wiiremote_stopsearch(); + wiiremote_stopsearch((WiiRemoteRef)refCon); } } //-------------------------------------------------------------------------------------------- -Boolean wiiremote_isconnected(void) +Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) { Boolean result; - result = gWiiRemote.device != nil && IOBluetoothDeviceIsConnected(gWiiRemote.device); + result = wiiremote->device != nil && IOBluetoothDeviceIsConnected(wiiremote->device); return result; } -Boolean wiiremote_search(void) +Boolean wiiremote_search(WiiRemoteRef wiiremote) { IOReturn ret; - if (gWiiRemote.inquiry != nil) + if (wiiremote->inquiry != nil) return true; - gWiiRemote.inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon(nil); - IOBluetoothDeviceInquirySetDeviceFoundCallback(gWiiRemote.inquiry, myFoundFunc); - IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(gWiiRemote.inquiry, myUpdatedFunc); - IOBluetoothDeviceInquirySetCompleteCallback(gWiiRemote.inquiry, myCompleteFunc); + wiiremote->inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon((void *)wiiremote); + IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); + IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); + IOBluetoothDeviceInquirySetCompleteCallback(wiiremote->inquiry, myCompleteFunc); - ret = IOBluetoothDeviceInquiryStart(gWiiRemote.inquiry); + ret = IOBluetoothDeviceInquiryStart(wiiremote->inquiry); if (ret != kIOReturnSuccess) { - IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry); - gWiiRemote.inquiry = nil; + IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); + wiiremote->inquiry = nil; return false; } return true; } -Boolean wiiremote_stopsearch(void) +Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) { IOReturn ret; - if (gWiiRemote.inquiry == nil) + if (wiiremote->inquiry == nil) { return true; // already stopped } - ret = IOBluetoothDeviceInquiryStop(gWiiRemote.inquiry); + ret = IOBluetoothDeviceInquiryStop(wiiremote->inquiry); if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted) { // kIOReturnNotPermitted is if it's already stopped } - IOBluetoothDeviceInquiryDelete(gWiiRemote.inquiry); - gWiiRemote.inquiry = nil; + IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); + wiiremote->inquiry = nil; return (ret==kIOReturnSuccess); } @@ -142,51 +140,52 @@ Boolean wiiremote_stopsearch(void) void myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) { - unsigned char *dp = (unsigned char*)data; + WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; + unsigned char *dp = (unsigned char*)data; - if (dp[1] == 0x20 && length >= 8) - { - gWiiRemote.batteryLevel = (double)dp[7]; - gWiiRemote.batteryLevel /= (double)0xC0; + if (dp[1] == 0x20 && length >= 8) + { + wiiremote->batteryLevel = (double)dp[7]; + wiiremote->batteryLevel /= (double)0xC0; - gWiiRemote.isExpansionPortUsed = (dp[4] & 0x02) != 0; - gWiiRemote.isLED1Illuminated = (dp[4] & 0x10) != 0; - gWiiRemote.isLED2Illuminated = (dp[4] & 0x20) != 0; - gWiiRemote.isLED3Illuminated = (dp[4] & 0x40) != 0; - gWiiRemote.isLED4Illuminated = (dp[4] & 0x80) != 0; + wiiremote->isExpansionPortUsed = (dp[4] & 0x02) != 0; + wiiremote->isLED1Illuminated = (dp[4] & 0x10) != 0; + wiiremote->isLED2Illuminated = (dp[4] & 0x20) != 0; + wiiremote->isLED3Illuminated = (dp[4] & 0x40) != 0; + wiiremote->isLED4Illuminated = (dp[4] & 0x80) != 0; - //have to reset settings (vibration, motion, IR and so on...) - wiiremote_irsensor(gWiiRemote.isIRSensorEnabled); - } + //have to reset settings (vibration, motion, IR and so on...) + wiiremote_irsensor(wiiremote, wiiremote->isIRSensorEnabled); + } if ((dp[1]&0xF0) == 0x30) { - gWiiRemote.buttonData = ((short)dp[2] << 8) + dp[3]; + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; if (dp[1] & 0x01) { - gWiiRemote.accX = dp[4]; - gWiiRemote.accY = dp[5]; - gWiiRemote.accZ = dp[6]; + wiiremote->accX = dp[4]; + wiiremote->accY = dp[5]; + wiiremote->accZ = dp[6]; - gWiiRemote.lowZ = gWiiRemote.lowZ * .9 + gWiiRemote.accZ * .1; - gWiiRemote.lowX = gWiiRemote.lowX * .9 + gWiiRemote.accX * .1; + wiiremote->lowZ = wiiremote->lowZ * .9 + wiiremote->accZ * .1; + wiiremote->lowX = wiiremote->lowX * .9 + wiiremote->accX * .1; - float absx = abs(gWiiRemote.lowX - 128); - float absz = abs(gWiiRemote.lowZ - 128); + float absx = abs(wiiremote->lowX - 128); + float absz = abs(wiiremote->lowZ - 128); - if (gWiiRemote.orientation == 0 || gWiiRemote.orientation == 2) absx -= 5; - if (gWiiRemote.orientation == 1 || gWiiRemote.orientation == 3) absz -= 5; + if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; + if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; if (absz >= absx) { if (absz > 5) - gWiiRemote.orientation = (gWiiRemote.lowZ > 128) ? 0 : 2; + wiiremote->orientation = (wiiremote->lowZ > 128) ? 0 : 2; } else { if (absx > 5) - gWiiRemote.orientation = (gWiiRemote.lowX > 128) ? 3 : 1; + wiiremote->orientation = (wiiremote->lowX > 128) ? 3 : 1; } //printf("orientation: %d\n", orientation); } @@ -196,65 +195,66 @@ Boolean wiiremote_stopsearch(void) int i; for(i=0 ; i<4 ; i++) { - gWiiRemote.irData[i].x = dp[7 + 3*i]; - gWiiRemote.irData[i].y = dp[8 + 3*i]; - gWiiRemote.irData[i].s = dp[9 + 3*i]; - gWiiRemote.irData[i].x += (gWiiRemote.irData[i].s & 0x30) << 4; - gWiiRemote.irData[i].y += (gWiiRemote.irData[i].s & 0xC0) << 2; - gWiiRemote.irData[i].s &= 0x0F; + wiiremote->irData[i].x = dp[7 + 3*i]; + wiiremote->irData[i].y = dp[8 + 3*i]; + wiiremote->irData[i].s = dp[9 + 3*i]; + wiiremote->irData[i].x += (wiiremote->irData[i].s & 0x30) << 4; + wiiremote->irData[i].y += (wiiremote->irData[i].s & 0xC0) << 2; + wiiremote->irData[i].s &= 0x0F; } } } float ox, oy; - if (gWiiRemote.irData[0].s < 0x0F && gWiiRemote.irData[1].s < 0x0F) + if (wiiremote->irData[0].s < 0x0F && wiiremote->irData[1].s < 0x0F) { - int l = gWiiRemote.leftPoint, r; - if (gWiiRemote.leftPoint == -1) + int l = wiiremote->leftPoint, r; + if (wiiremote->leftPoint == -1) { // printf("Tracking.\n"); - switch (gWiiRemote.orientation) + switch (wiiremote->orientation) { - case 0: l = (gWiiRemote.irData[0].x < gWiiRemote.irData[1].x) ? 0 : 1; break; - case 1: l = (gWiiRemote.irData[0].y > gWiiRemote.irData[1].y) ? 0 : 1; break; - case 2: l = (gWiiRemote.irData[0].x > gWiiRemote.irData[1].x) ? 0 : 1; break; - case 3: l = (gWiiRemote.irData[0].y < gWiiRemote.irData[1].y) ? 0 : 1; break; + case 0: l = (wiiremote->irData[0].x < wiiremote->irData[1].x) ? 0 : 1; break; + case 1: l = (wiiremote->irData[0].y > wiiremote->irData[1].y) ? 0 : 1; break; + case 2: l = (wiiremote->irData[0].x > wiiremote->irData[1].x) ? 0 : 1; break; + case 3: l = (wiiremote->irData[0].y < wiiremote->irData[1].y) ? 0 : 1; break; } - gWiiRemote.leftPoint = l; + wiiremote->leftPoint = l; } r = 1-l; - float dx = gWiiRemote.irData[r].x - gWiiRemote.irData[l].x; - float dy = gWiiRemote.irData[r].y - gWiiRemote.irData[l].y; + float dx = wiiremote->irData[r].x - wiiremote->irData[l].x; + float dy = wiiremote->irData[r].y - wiiremote->irData[l].y; float d = sqrt(dx*dx+dy*dy); dx /= d; dy /= d; - float cx = (gWiiRemote.irData[l].x+gWiiRemote.irData[r].x)/1024.0 - 1; - float cy = (gWiiRemote.irData[l].y+gWiiRemote.irData[r].y)/1024.0 - .75; + float cx = (wiiremote->irData[l].x+wiiremote->irData[r].x)/1024.0 - 1; + float cy = (wiiremote->irData[l].y+wiiremote->irData[r].y)/1024.0 - .75; - gWiiRemote.angle = atan2(dy, dx); + wiiremote->angle = atan2(dy, dx); ox = -dy*cy-dx*cx; oy = -dx*cy+dy*cx; //printf("x:%5.2f; y: %5.2f; angle: %5.1f\n", ox, oy, angle*180/M_PI); - gWiiRemote.tracking = true; + wiiremote->tracking = true; } else { // printf("Not tracking.\n"); ox = oy = -100; - gWiiRemote.leftPoint = -1; - gWiiRemote.tracking = false; + wiiremote->angle = -100; + wiiremote->leftPoint = -1; + wiiremote->tracking = false; } - gWiiRemote.posX = ox; - gWiiRemote.posY = oy; + wiiremote->posX = ox; + wiiremote->posY = oy; } void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) @@ -282,29 +282,32 @@ void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOB //-------------------------------------------------------------------------------------------- -Boolean wiiremote_connect(void) +Boolean wiiremote_connect(WiiRemoteRef wiiremote) { + IOReturn ret; short i; - if (gWiiRemote.device == nil) + if (wiiremote->device == nil) return false; // connect the device for (i=0; idevice, nil, nil); + if ( ret == kIOReturnSuccess) break; usleep(10000); // wait 10ms } if (i==kTrial) return false; - gWiiRemote.disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(gWiiRemote.device, myDisconnectedFunc, 0); + wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, 0); // performs an SDP query for (i=0; idevice, nil, nil); + if ( ret == kIOReturnSuccess) break; usleep(10000); // wait 10ms } @@ -314,84 +317,86 @@ Boolean wiiremote_connect(void) // open L2CAPChannel : BluetoothL2CAPPSM = 17 for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) break; usleep(10000); // wait 10ms } if (i==kTrial) { - gWiiRemote.cchan = nil; - IOBluetoothDeviceCloseConnection(gWiiRemote.device); - gWiiRemote.device = nil; + wiiremote->cchan = nil; + IOBluetoothDeviceCloseConnection(wiiremote->device); + wiiremote->device = nil; return false; } // open L2CAPChannel : BluetoothL2CAPPSM = 19 for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) break; usleep(10000); // wait 10ms } if (i==kTrial) { - gWiiRemote.ichan = nil; - IOBluetoothL2CAPChannelCloseChannel(gWiiRemote.cchan); - IOBluetoothDeviceCloseConnection(gWiiRemote.device); - gWiiRemote.device = nil; + wiiremote->ichan = nil; + IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); + IOBluetoothDeviceCloseConnection(wiiremote->device); + wiiremote->device = nil; return false; } - wiiremote_motionsensor(true); - wiiremote_irsensor(false); - wiiremote_vibration(false); - wiiremote_led(false, false, false, false); + wiiremote_motionsensor(wiiremote, true); + wiiremote_irsensor(wiiremote, false); + wiiremote_vibration(wiiremote, false); + wiiremote_led(wiiremote, false, false, false, false); return true; } -Boolean wiiremote_disconnect(void) +Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) { short i; - if (gWiiRemote.disconnectNotification != nil) + if (wiiremote->disconnectNotification != nil) { - IOBluetoothUserNotificationUnregister(gWiiRemote.disconnectNotification); - gWiiRemote.disconnectNotification = nil; + IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); + wiiremote->disconnectNotification = nil; } - if (gWiiRemote.cchan && IOBluetoothDeviceIsConnected(gWiiRemote.device)) + if (wiiremote->cchan && IOBluetoothDeviceIsConnected(wiiremote->device)) { for (i=0; icchan) == kIOReturnSuccess) { - gWiiRemote.cchan = nil; + wiiremote->cchan = nil; break; } } if (i==kTrial) return false; } - if (gWiiRemote.ichan && IOBluetoothDeviceIsConnected(gWiiRemote.device)) + if (wiiremote->ichan && IOBluetoothDeviceIsConnected(wiiremote->device)) { for (i=0; iichan) == kIOReturnSuccess) { - gWiiRemote.ichan = nil; + wiiremote->ichan = nil; break; } } if (i==kTrial) return false; } - if (gWiiRemote.device && IOBluetoothDeviceIsConnected(gWiiRemote.device)) + if (wiiremote->device && IOBluetoothDeviceIsConnected(wiiremote->device)) { for (i=0; idevice) == kIOReturnSuccess) { break; } @@ -399,10 +404,10 @@ Boolean wiiremote_disconnect(void) if (i==kTrial) return false; } - if (gWiiRemote.device != nil) + if (wiiremote->device != nil) { - IOBluetoothObjectRelease(gWiiRemote.device); - gWiiRemote.device = nil; + IOBluetoothObjectRelease(wiiremote->device); + wiiremote->device = nil; } return true; @@ -411,7 +416,7 @@ Boolean wiiremote_disconnect(void) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -Boolean sendCommand(unsigned char *data, size_t length) +Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, size_t length) { unsigned char buf[40]; IOReturn ret; @@ -427,7 +432,7 @@ Boolean sendCommand(unsigned char *data, size_t length) for (i = 0; icchan, buf, length); if (ret == kIOReturnSuccess) break; usleep(10000); @@ -436,10 +441,10 @@ Boolean sendCommand(unsigned char *data, size_t length) return (ret==kIOReturnSuccess); } -Boolean writeData(const unsigned char *data, unsigned long address, size_t length) +Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, size_t length) { unsigned char cmd[22]; - int i; + unsigned int i; for(i=0 ; iisVibrationEnabled) cmd[1] |= 0x01; data = cmd; - return sendCommand(cmd, 22); + return sendCommand(wiiremote, cmd, 22); } //-------------------------------------------------------------------------------------------- -Boolean wiiremote_motionsensor(Boolean enabled) +Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled) { - gWiiRemote.isMotionSensorEnabled = enabled; + wiiremote->isMotionSensorEnabled = enabled; unsigned char cmd[] = {0x12, 0x00, 0x30}; - if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; - if (gWiiRemote.isMotionSensorEnabled) cmd[2] |= 0x01; - if (gWiiRemote.isIRSensorEnabled) cmd[2] |= 0x02; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; + if (wiiremote->isIRSensorEnabled) cmd[2] |= 0x02; - return sendCommand(cmd, 3); + return sendCommand(wiiremote, cmd, 3); } -Boolean wiiremote_irsensor(Boolean enabled) +Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) { IOReturn ret; - gWiiRemote.isIRSensorEnabled = enabled; + wiiremote->isIRSensorEnabled = enabled; // set register 0x12 (report type) - if (ret = wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled)) return ret; + if (ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled) == false) return ret; // set register 0x13 (ir enable/vibe) - if (ret = wiiremote_vibration(gWiiRemote.isVibrationEnabled)) return ret; + if (ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled) == false) return ret; // set register 0x1a (ir enable 2) unsigned char cmd[] = {0x1a, 0x00}; if (enabled) cmd[1] |= 0x04; - if (ret = sendCommand(cmd, 2)) return ret; + if (ret = sendCommand(wiiremote, cmd, 2) == false) return ret; if(enabled){ // based on marcan's method, found on wiili wiki: @@ -497,65 +502,65 @@ Boolean wiiremote_irsensor(Boolean enabled) // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) // the sleeps help it it seems usleep(10000); - if (ret = writeData((darr){0x01}, 0x04B00030, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1) == false) return ret; usleep(10000); - if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1) == false) return ret; usleep(10000); - if (ret = writeData((darr){0x90}, 0x04B00006, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0x90}, 0x04B00006, 1) == false) return ret; usleep(10000); - if (ret = writeData((darr){0xC0}, 0x04B00008, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0xC0}, 0x04B00008, 1) == false) return ret; usleep(10000); - if (ret = writeData((darr){0x40}, 0x04B0001A, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0x40}, 0x04B0001A, 1) == false) return ret; usleep(10000); - if (ret = writeData((darr){0x33}, 0x04B00033, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0x33}, 0x04B00033, 1) == false) return ret; usleep(10000); - if (ret = writeData((darr){0x08}, 0x04B00030, 1)) return ret; + if (ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1) == false) return ret; }else{ // probably should do some writes to power down the camera, save battery // but don't know how yet. //bug fix #1614587 - wiiremote_motionsensor(gWiiRemote.isMotionSensorEnabled); - wiiremote_vibration(gWiiRemote.isVibrationEnabled); + wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); + wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); } return true; } -Boolean wiiremote_vibration(Boolean enabled) +Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled) { - gWiiRemote.isVibrationEnabled = enabled; + wiiremote->isVibrationEnabled = enabled; unsigned char cmd[] = {0x13, 0x00}; - if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; - if (gWiiRemote.isIRSensorEnabled) cmd[1] |= 0x04; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; - return sendCommand(cmd, 2);; + return sendCommand(wiiremote, cmd, 2);; } -Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) +Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) { unsigned char cmd[] = {0x11, 0x00}; - if (gWiiRemote.isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; if (enabled1) cmd[1] |= 0x10; if (enabled2) cmd[1] |= 0x20; if (enabled3) cmd[1] |= 0x40; if (enabled4) cmd[1] |= 0x80; - gWiiRemote.isLED1Illuminated = enabled1; - gWiiRemote.isLED2Illuminated = enabled2; - gWiiRemote.isLED3Illuminated = enabled3; - gWiiRemote.isLED4Illuminated = enabled4; + wiiremote->isLED1Illuminated = enabled1; + wiiremote->isLED2Illuminated = enabled2; + wiiremote->isLED3Illuminated = enabled3; + wiiremote->isLED4Illuminated = enabled4; - return sendCommand(cmd, 2); + return sendCommand(wiiremote, cmd, 2); } -void wiiremote_getstatus(void) +Boolean wiiremote_getstatus(WiiRemoteRef wiiremote) { unsigned char cmd[] = {0x15, 0x00}; - sendCommand(cmd, 2); + return sendCommand(wiiremote, cmd, 2); } diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h index 730682c..66ec4ac 100644 --- a/wiiremote/wiiremote.h +++ b/wiiremote/wiiremote.h @@ -5,7 +5,6 @@ #include #include #include - #include #include @@ -50,14 +49,14 @@ typedef struct _WiiRemoteRec IOBluetoothUserNotificationRef disconnectNotification; } WiiRemoteRec, *WiiRemoteRef; -WiiRemoteRef wiiremote_init(void); -Boolean wiiremote_isconnected(void); -Boolean wiiremote_search(void); -Boolean wiiremote_stopsearch(void); -Boolean wiiremote_connect(void); -Boolean wiiremote_disconnect(void); -Boolean wiiremote_motionsensor(Boolean enabled); -Boolean wiiremote_irsensor(Boolean enabled); -Boolean wiiremote_vibration(Boolean enabled); -Boolean wiiremote_led(Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); -void wiiremote_getstatus(void); +void wiiremote_init(WiiRemoteRef wiiremote); +Boolean wiiremote_isconnected(WiiRemoteRef wiiremote); +Boolean wiiremote_search(WiiRemoteRef wiiremote); +Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote); +Boolean wiiremote_connect(WiiRemoteRef wiiremote); +Boolean wiiremote_disconnect(WiiRemoteRef wiiremote); +Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); +Boolean wiiremote_getstatus(WiiRemoteRef wiiremote); -- cgit v1.2.1 From 003f2efe5e176b135ce690fc57b033bdb257dbb1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 3 Jan 2007 01:01:08 +0000 Subject: oops, forgot to allocate memory to the pointer! tsk tsk... svn path=/trunk/externals/io/; revision=7132 --- wiiremote/aka.wiiremote.c | 1 + 1 file changed, 1 insertion(+) diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 662f94e..5780c43 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -310,6 +310,7 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) #ifdef PD t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); // add in 1.0B4 if (x->wiiremote != nil) wiiremote_init(x->wiiremote); -- cgit v1.2.1 From b0c3cca8b4dcfe151d073a7f711f96020d2925fc Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 17 May 2007 04:58:19 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r7680, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/io/; revision=7681 --- wiiremote/HISTORY.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 wiiremote/HISTORY.txt diff --git a/wiiremote/HISTORY.txt b/wiiremote/HISTORY.txt new file mode 100644 index 0000000..fd50e7d --- /dev/null +++ b/wiiremote/HISTORY.txt @@ -0,0 +1,30 @@ +aka.wiiremote Version History + +1.0B5 : 2007.02.03 + +- Nunchuk is supported. +( Classic Controller is NOT supported.) +- device address is supported. +- outlets and output messages are changed. +- some input messages are simplified. +- help patch is expanded for Nunchuk. + +1.0B4 : 2006.12.24 + +- multiple Wii remotes are supported. + +1.0B3 : 2006.12.20 + +- data acquisition is improved. +- unusual vibration sound is resolved. + +1.0B2 : 2006.12.15 + +- connection/disconnection is improved. +- IR sensor is supported. +- status report is supported +- help patch is rewritten. + +1.0B1 : 2006.12.12 + +- first release \ No newline at end of file -- cgit v1.2.1 From bc84a83351307d08588b086634b159c186cede81 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 17 May 2007 05:14:27 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r7683, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/io/; revision=7684 --- wiiremote/HISTORY.txt | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/wiiremote/HISTORY.txt b/wiiremote/HISTORY.txt index fd50e7d..a0687b1 100644 --- a/wiiremote/HISTORY.txt +++ b/wiiremote/HISTORY.txt @@ -1,4 +1,24 @@ -aka.wiiremote Version History +aka.wiiremote Version History + +1.0B6 : 2007.04.24 + +- The Classic Controller is supported. +- The help patch is updated. +- The URLs in [info] subpatch are updated. + +- 'expansion' message enables to use the expansion controller(Nunchuk or Classic Controller). +- 'nunchuk' message is obsolete. + You should use 'expansion' instead of it even though you can use it for the backward compatibility only. + +- The IR sensor and the expansion controller (ex. Nunchuk) can be used together. + +- The stability on PPC-Mac is a little improved. + You have to do the following steps every time you use the Wii Remote on PPC-Mac. + (You would set up only once on Intel-Mac.) +1: Delete "Nintendo RVL-CNT-01" on "Device" tab in "Bluetooth" System Preference. +2: Do the setup for Wii Remote. See http://max.iamas.ac.jp/2061/articles/121.html +3: Open "aka.wiiremote.help" and connect it. + 1.0B5 : 2007.02.03 @@ -9,15 +29,18 @@ aka.wiiremote Version History - some input messages are simplified. - help patch is expanded for Nunchuk. + 1.0B4 : 2006.12.24 - multiple Wii remotes are supported. + 1.0B3 : 2006.12.20 - data acquisition is improved. - unusual vibration sound is resolved. + 1.0B2 : 2006.12.15 - connection/disconnection is improved. @@ -25,6 +48,7 @@ aka.wiiremote Version History - status report is supported - help patch is rewritten. + 1.0B1 : 2006.12.12 - first release \ No newline at end of file -- cgit v1.2.1 From 6429a44f369c05270faa22fa17be45e3ea05aa96 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 17 May 2007 05:15:02 +0000 Subject: cleaned up some things in prep for importing new code svn path=/trunk/externals/io/; revision=7686 --- wiiremote/aka.wiiremote_b2_pd-port.patch | 223 ------------------------------- wiiremote/aka.wiiremote_b3_pd-port.patch | 176 ------------------------ wiiremote/aka.wiiremote_b4_pd-port.patch | 186 -------------------------- wiiremote/wiiremote-help.pd | 38 +++--- 4 files changed, 23 insertions(+), 600 deletions(-) delete mode 100644 wiiremote/aka.wiiremote_b2_pd-port.patch delete mode 100644 wiiremote/aka.wiiremote_b3_pd-port.patch delete mode 100644 wiiremote/aka.wiiremote_b4_pd-port.patch diff --git a/wiiremote/aka.wiiremote_b2_pd-port.patch b/wiiremote/aka.wiiremote_b2_pd-port.patch deleted file mode 100644 index 3f96112..0000000 --- a/wiiremote/aka.wiiremote_b2_pd-port.patch +++ /dev/null @@ -1,223 +0,0 @@ ---- /Users/hans/Desktop/aka.wiiremote-b2-src/aka.wiiremote.c 2006-12-15 08:36:06.000000000 -0500 -+++ aka.wiiremote.c 2006-12-16 17:05:31.000000000 -0500 -@@ -1,15 +1,28 @@ - // aka.wiiremote.c - // Copyright by Masayuki Akamatsu -+// port to Pd by Hans-Christoph Steiner - -+ -+#ifdef PD -+#include "m_pd.h" -+#define SETLONG SETFLOAT -+static t_class *wiiremote_class; -+#else /* Max */ - #include "ext.h" -+#endif - #include "wiiremote.h" - - #define kInterval 100 - #define kMaxTrial 100 - -+ - typedef struct _akawiiremote - { -+#ifdef PD -+ t_object x_obj; -+#else /* Max */ - struct object obj; -+#endif - - WiiRemoteRef wiiremote; - -@@ -44,6 +57,36 @@ - void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); - void akawiiremote_free(t_akawiiremote *x); - -+#ifdef PD -+void wiiremote_setup() -+{ -+ wiiremote_class = class_new(gensym("wiiremote"), -+ (t_newmethod)akawiiremote_new, -+ (t_method)akawiiremote_free, -+ sizeof(t_akawiiremote), -+ CLASS_DEFAULT, -+ A_GIMME,0); -+ -+ class_addbang(wiiremote_class,(t_method)akawiiremote_bang); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); -+ -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); -+ -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); -+ -+ post("aka.wiiremote 1.0B2-UB by Masayuki Akamatsu"); -+ post("\tPd port by Hans-Christoph Steiner"); -+ -+ akawiiremote_count = 0; -+} -+#else /* Max */ - void main() - { - setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); -@@ -66,7 +109,7 @@ - - akawiiremote_count = 0; - } -- -+#endif /* PD */ - //-------------------------------------------------------------------------------------------- - - void akawiiremote_bang(t_akawiiremote *x) -@@ -76,6 +119,27 @@ - if (x->wiiremote->device == nil) - return; // do nothing - -+#ifdef PD -+ outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); -+ -+ if (x->wiiremote->isIRSensorEnabled) -+ { -+ SETFLOAT(list, x->wiiremote->posX); -+ SETFLOAT(list + 1, x->wiiremote->posY); -+ SETFLOAT(list + 2, x->wiiremote->angle); -+ SETFLOAT (list + 3, x->wiiremote->tracking); -+ outlet_list(x->irOut, &s_list, 4, list); -+ } -+ -+ if (x->wiiremote->isMotionSensorEnabled) -+ { -+ SETFLOAT(list, x->wiiremote->accX); -+ SETFLOAT(list + 1, x->wiiremote->accY); -+ SETFLOAT(list + 2, x->wiiremote->accZ); -+ SETFLOAT(list + 3, x->wiiremote->orientation); -+ outlet_list(x->accOut, &s_list, 4, list); -+ } -+#else /* Max */ - outlet_int(x->buttonsOut, x->wiiremote->buttonData); - - if (x->wiiremote->isIRSensorEnabled) -@@ -95,6 +159,7 @@ - SETLONG(list + 3, x->wiiremote->orientation); - outlet_list(x->accOut, 0L, 4, &list); - } -+#endif /* PD */ - - wiiremote_getstatus(); - } -@@ -173,11 +238,19 @@ - { - t_atom list[4]; - -+#ifdef PD -+ SETFLOAT(list, x->wiiremote->isLED1Illuminated); -+ SETFLOAT(list + 1, x->wiiremote->isLED2Illuminated); -+ SETFLOAT(list + 2, x->wiiremote->isLED3Illuminated); -+ SETFLOAT(list + 3, x->wiiremote->isLED4Illuminated); -+ outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); -+#else /* Max */ - SETLONG(list, x->wiiremote->isLED1Illuminated); - SETLONG(list + 1, x->wiiremote->isLED2Illuminated); - SETLONG(list + 2, x->wiiremote->isLED3Illuminated); - SETLONG(list + 3, x->wiiremote->isLED4Illuminated); - outlet_anything(x->statusOut, gensym("ledstatus"), 4, &list); -+#endif - } - - //-------------------------------------------------------------------------------------------- -@@ -222,11 +295,13 @@ - - void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) - { -+#ifndef PD /* Max */ - if (m==ASSIST_INLET) - { - sprintf(s,"connect, bang, disconnect...."); - } - else -+#endif /* NOT PD */ - { - switch(a) - { -@@ -242,6 +317,17 @@ - - void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) - { -+#ifdef PD -+ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); -+ -+ x->clock = clock_new(x, (t_method)akawiiremote_clock); -+ -+ /* create anything outlet used for HID data */ -+ x->statusOut = outlet_new(&x->x_obj, 0); -+ x->buttonsOut = outlet_new(&x->x_obj, &s_float); -+ x->irOut = outlet_new(&x->x_obj, &s_list); -+ x->accOut = outlet_new(&x->x_obj, &s_list); -+#else /* Max */ - t_akawiiremote *x; - - x = (t_akawiiremote *)newobject(akawiiremote_class); -@@ -249,13 +335,15 @@ - x->wiiremote = wiiremote_init(); - - x->clock = clock_new(x, (method)akawiiremote_clock); -- x->trial = 0; -- x->interval = kInterval; - - x->statusOut = outlet_new(x, 0); - x->buttonsOut = intout(x); - x->irOut = listout(x); - x->accOut = listout(x); -+#endif /* PD */ -+ x->trial = 0; -+ x->interval = kInterval; -+ - - akawiiremote_count++; - return x; -@@ -267,6 +355,12 @@ - if (akawiiremote_count == 0) - wiiremote_disconnect(); - -+#ifdef PD -+ if (x->clock) -+ clock_unset(x->clock); -+ clock_free(x->clock); -+#else /* Max */ - freeobject(x->clock); -+#endif - } - ---- /Users/hans/Desktop/aka.wiiremote-b2-src/wiiremote.h 2006-12-14 10:21:42.000000000 -0500 -+++ wiiremote.h 2006-12-16 16:48:38.000000000 -0500 -@@ -2,9 +2,13 @@ - // Copyright by Masayuki Akamatsu - // Based on "DarwiinRemote" by Hiroaki Kimura - -+#include - #include - #include - -+#include -+#include -+ - typedef struct { - int x, y, s; - } IRData; ---- /Users/hans/Desktop/aka.wiiremote-b2-src/wiiremote.c 2006-12-15 08:31:05.000000000 -0500 -+++ wiiremote.c 2006-12-16 17:12:14.000000000 -0500 -@@ -4,6 +4,8 @@ - - #include "wiiremote.h" - -+#include -+ - // this type is used a lot (data array): - typedef unsigned char darr[]; - diff --git a/wiiremote/aka.wiiremote_b3_pd-port.patch b/wiiremote/aka.wiiremote_b3_pd-port.patch deleted file mode 100644 index 8609c62..0000000 --- a/wiiremote/aka.wiiremote_b3_pd-port.patch +++ /dev/null @@ -1,176 +0,0 @@ ---- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b3-src/wiiremote.h 2006-12-20 05:29:31.000000000 -0500 -+++ wiiremote.h 2006-12-28 01:36:00.000000000 -0500 -@@ -2,8 +2,13 @@ - // Copyright by Masayuki Akamatsu - // Based on "DarwiinRemote" by Hiroaki Kimura - -+#include -+#include - #include - -+#include -+#include -+ - typedef struct { - int x, y, s; - } IRData; ---- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b3-src/aka.wiiremote.c 2006-12-20 06:09:10.000000000 -0500 -+++ aka.wiiremote.c 2006-12-28 17:47:08.000000000 -0500 -@@ -4,15 +4,28 @@ - // 1.0B2 : 2006.12.15 - // 1.0B3 : 2006.12.20 - -+#ifdef PD -+#include "m_pd.h" -+#define SETLONG SETFLOAT -+static t_class *wiiremote_class; -+#else /* Max */ - #include "ext.h" -+#endif /* PD */ -+ - #include "wiiremote.h" - -+#include -+ - #define kInterval 100 - #define kMaxTrial 100 - - typedef struct _akawiiremote - { -+#ifdef PD -+ t_object x_obj; -+#else /* Max */ - struct object obj; -+#endif - - WiiRemoteRef wiiremote; - -@@ -47,7 +60,11 @@ - void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); - void akawiiremote_free(t_akawiiremote *x); - -+#ifdef PD -+void wiiremote_setup() -+#else /* Max */ - void main() -+#endif /* PD */ - { - NumVersion outSoftwareVersion; - BluetoothHCIVersionInfo outHardwareVersion; -@@ -66,6 +83,32 @@ - return; - } - -+ post("aka.wiiremote 1.0B3-UB by Masayuki Akamatsu"); -+ -+#ifdef PD -+ post("\tPd port by Hans-Christoph Steiner"); -+ -+ wiiremote_class = class_new(gensym("wiiremote"), -+ (t_newmethod)akawiiremote_new, -+ (t_method)akawiiremote_free, -+ sizeof(t_akawiiremote), -+ CLASS_DEFAULT, -+ A_GIMME,0); -+ -+ class_addbang(wiiremote_class,(t_method)akawiiremote_bang); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); -+ -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); -+ -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); -+#else /* Max */ - setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); - - addbang((method)akawiiremote_bang); -@@ -81,8 +124,7 @@ - addmess((method)akawiiremote_getledstatus,"getledstatus",0); - - addmess((method)akawiiremote_assist,"assist",A_CANT,0); -- -- post("aka.wiiremote 1.0B3-UB by Masayuki Akamatsu"); -+#endif /* PD */ - - akawiiremote_count = 0; - } -@@ -96,7 +138,11 @@ - if (x->wiiremote->device == nil) - return; // do nothing - -+#ifdef PD -+ outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); -+#else /* Max */ - outlet_int(x->buttonsOut, x->wiiremote->buttonData); -+#endif /* PD */ - - if (x->wiiremote->isIRSensorEnabled) - { -@@ -244,11 +290,13 @@ - - void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) - { -+#ifndef PD /* Max */ - if (m==ASSIST_INLET) - { - sprintf(s,"connect, bang, disconnect...."); - } - else -+#endif /* NOT PD */ - { - switch(a) - { -@@ -264,6 +312,19 @@ - - void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) - { -+#ifdef PD -+ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); -+ -+ x->wiiremote = wiiremote_init(); -+ -+ x->clock = clock_new(x, (t_method)akawiiremote_clock); -+ -+ /* create anything outlet used for HID data */ -+ x->statusOut = outlet_new(&x->x_obj, 0); -+ x->buttonsOut = outlet_new(&x->x_obj, &s_float); -+ x->irOut = outlet_new(&x->x_obj, &s_list); -+ x->accOut = outlet_new(&x->x_obj, &s_list); -+#else /* Max */ - t_akawiiremote *x; - - x = (t_akawiiremote *)newobject(akawiiremote_class); -@@ -271,13 +332,14 @@ - x->wiiremote = wiiremote_init(); - - x->clock = clock_new(x, (method)akawiiremote_clock); -- x->trial = 0; -- x->interval = kInterval; - - x->statusOut = outlet_new(x, 0); - x->buttonsOut = intout(x); - x->irOut = listout(x); - x->accOut = listout(x); -+#endif /* PD */ -+ x->trial = 0; -+ x->interval = kInterval; - - akawiiremote_count++; - return x; -@@ -290,6 +352,10 @@ - wiiremote_disconnect(); - - clock_unset(x->clock); -+#ifdef PD -+ clock_free(x->clock); -+#else /* Max */ - freeobject((t_object *)x->clock); -+#endif /* PD */ - } - diff --git a/wiiremote/aka.wiiremote_b4_pd-port.patch b/wiiremote/aka.wiiremote_b4_pd-port.patch deleted file mode 100644 index 0edf592..0000000 --- a/wiiremote/aka.wiiremote_b4_pd-port.patch +++ /dev/null @@ -1,186 +0,0 @@ ---- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b4-src/wiiremote.c 2006-12-23 09:52:07.000000000 -0500 -+++ wiiremote.c 2006-12-28 18:11:52.000000000 -0500 -@@ -444,7 +444,7 @@ - Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, size_t length) - { - unsigned char cmd[22]; -- int i; -+ unsigned int i; - - for(i=0 ; i -+#include - #include -+#include -+#include - - typedef struct { - int x, y, s; ---- /Users/hans/Documents/Research/HID/wiiremote/aka.wiiremote-b4-src/aka.wiiremote.c 2006-12-22 19:18:31.000000000 -0500 -+++ aka.wiiremote.c 2006-12-28 18:09:23.000000000 -0500 -@@ -4,15 +4,27 @@ - // 1.0B2 : 2006.12.15 - // 1.0B3 : 2006.12.20 - -+#ifdef PD -+#include "m_pd.h" -+#define SETLONG SETFLOAT -+static t_class *wiiremote_class; -+#else /* Max */ - #include "ext.h" -+#endif /* PD */ -+ - #include "wiiremote.h" -+#include - - #define kInterval 100 - #define kMaxTrial 100 - - typedef struct _akawiiremote - { -+#ifdef PD -+ t_object x_obj; -+#else /* Max */ - struct object obj; -+#endif - - WiiRemoteRef wiiremote; - -@@ -45,7 +57,11 @@ - void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); - void akawiiremote_free(t_akawiiremote *x); - -+#ifdef PD -+void wiiremote_setup() -+#else /* Max */ - void main() -+#endif /* PD */ - { - NumVersion outSoftwareVersion; - BluetoothHCIVersionInfo outHardwareVersion; -@@ -64,6 +80,32 @@ - return; - } - -+ post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); -+ -+#ifdef PD -+ post("\tPd port by Hans-Christoph Steiner"); -+ -+ wiiremote_class = class_new(gensym("wiiremote"), -+ (t_newmethod)akawiiremote_new, -+ (t_method)akawiiremote_free, -+ sizeof(t_akawiiremote), -+ CLASS_DEFAULT, -+ A_GIMME,0); -+ -+ class_addbang(wiiremote_class,(t_method)akawiiremote_bang); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); -+ -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); -+ -+ class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); -+#else /* Max */ - setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); - - addbang((method)akawiiremote_bang); -@@ -79,9 +121,7 @@ - addmess((method)akawiiremote_getledstatus,"getledstatus",0); - - addmess((method)akawiiremote_assist,"assist",A_CANT,0); -- -- post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); -- -+#endif /* PD */ - } - - //-------------------------------------------------------------------------------------------- -@@ -93,7 +133,11 @@ - if (x->wiiremote->device == nil) - return; // do nothing - -+#ifdef PD -+ outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); -+#else /* Max */ - outlet_int(x->buttonsOut, x->wiiremote->buttonData); -+#endif /* PD */ - - if (x->wiiremote->isIRSensorEnabled) - { -@@ -241,11 +285,13 @@ - - void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) - { -+#ifndef PD /* Max */ - if (m==ASSIST_INLET) - { - sprintf(s,"connect, bang, disconnect...."); - } - else -+#endif /* NOT PD */ - { - switch(a) - { -@@ -261,6 +307,20 @@ - - void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) - { -+#ifdef PD -+ t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); -+ -+ if (x->wiiremote != nil) -+ wiiremote_init(x->wiiremote); -+ -+ x->clock = clock_new(x, (t_method)akawiiremote_clock); -+ -+ /* create anything outlet used for HID data */ -+ x->statusOut = outlet_new(&x->x_obj, 0); -+ x->buttonsOut = outlet_new(&x->x_obj, &s_float); -+ x->irOut = outlet_new(&x->x_obj, &s_list); -+ x->accOut = outlet_new(&x->x_obj, &s_list); -+#else /* Max */ - t_akawiiremote *x; - - x = (t_akawiiremote *)newobject(akawiiremote_class); -@@ -270,13 +330,14 @@ - wiiremote_init(x->wiiremote); - - x->clock = clock_new(x, (method)akawiiremote_clock); -- x->trial = 0; -- x->interval = kInterval; - - x->statusOut = outlet_new(x, 0); - x->buttonsOut = intout(x); - x->irOut = listout(x); - x->accOut = listout(x); -+#endif /* PD */ -+ x->trial = 0; -+ x->interval = kInterval; - - return x; - } -@@ -290,6 +351,10 @@ - } - - clock_unset(x->clock); -+#ifdef PD -+ clock_free(x->clock); -+#else /* Max */ - freeobject((t_object *)x->clock); -+#endif /* PD */ - } - diff --git a/wiiremote/wiiremote-help.pd b/wiiremote/wiiremote-help.pd index b3faed8..737fe6b 100644 --- a/wiiremote/wiiremote-help.pd +++ b/wiiremote/wiiremote-help.pd @@ -1,21 +1,29 @@ -#N canvas 41 171 573 456 10; +#N canvas 41 171 577 460 10; #X obj 451 21 import io; -#X obj 169 251 wiiremote; -#X msg 124 70 connect; -#X msg 141 96 disconnect; -#X msg 242 100 motionsensor \$1; -#X obj 242 78 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +#X obj 213 388 wiiremote; +#X msg 168 207 connect; +#X msg 185 233 disconnect; +#X msg 286 237 motionsensor \$1; +#X obj 286 215 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 406 215 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 406 237 irsensor \$1; +#X obj 64 254 metro 100; +#X obj 64 233 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 ; -#X obj 362 78 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 +#X msg 376 290 getbatterylevel; +#X msg 376 310 getledstatus; +#X msg 376 330 getexpansionstatus; +#X msg 129 283 bang; +#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote +with your computer (only required for the first use).; +#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs +will start blinking.; +#X text 49 109 - Click on the [connect( message \, the LEDs will stop +blinking once its connected; +#X text 49 139 - Start the [metro] to get updates from [wiiremote] ; -#X msg 362 100 irsensor \$1; -#X obj 20 117 metro 100; -#X obj 20 96 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 -; -#X msg 332 153 getbatterylevel; -#X msg 332 173 getledstatus; -#X msg 332 193 getexpansionstatus; -#X msg 85 146 bang; #X connect 2 0 1 0; #X connect 3 0 1 0; #X connect 4 0 1 0; -- cgit v1.2.1 From 2e3417388d79966bed87965155b3f5f485728a4a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 17 May 2007 05:33:45 +0000 Subject: merged in b6 and got it compiling, lots of warning, I would be surprised if it actually works svn path=/trunk/externals/io/; revision=7687 --- wiiremote/aka.wiiremote.c | 443 +++++++++++++------ wiiremote/wiiremote.c | 1026 ++++++++++++++++++++++++++++++++++----------- wiiremote/wiiremote.h | 123 +++++- 3 files changed, 1215 insertions(+), 377 deletions(-) diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 5780c43..9d945b1 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -1,12 +1,18 @@ // aka.wiiremote.c // Copyright by Masayuki Akamatsu +// Code for PD by Hans-Christoph Steiner // 1.0B1 : 2006.12.12 // 1.0B2 : 2006.12.15 // 1.0B3 : 2006.12.20 +// 1.0B4 : 2006.12.24 +// 1.0B5 : 2007.02.03 +// 1.0B6 : 2007.04.24 #ifdef PD #include "m_pd.h" +#define SETSYM SETSYMBOL #define SETLONG SETFLOAT +#define method t_method static t_class *wiiremote_class; #else /* Max */ #include "ext.h" @@ -27,36 +33,42 @@ typedef struct _akawiiremote #endif WiiRemoteRef wiiremote; + char address[32]; void *clock; - long interval; - long trial; + Boolean connected; void *statusOut; - void *buttonsOut; - void *irOut; - void *accOut; + void *dataOut } t_akawiiremote; void *akawiiremote_class; // the number of instance of this object void akawiiremote_bang(t_akawiiremote *x); +void akawiiremote_address(t_akawiiremote *x, t_symbol *s); void akawiiremote_connect(t_akawiiremote *x); void akawiiremote_disconnect(t_akawiiremote *x); void akawiiremote_motionsensor(t_akawiiremote *x, long enable); void akawiiremote_irsensor(t_akawiiremote *x, long enable); void akawiiremote_vibration(t_akawiiremote *x, long enable); void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4); +void akawiiremote_expansion(t_akawiiremote *x, long enable); -void akawiiremote_getbatterylevel(t_akawiiremote *x); -void akawiiremote_getexpansionstatus(t_akawiiremote *x); -void akawiiremote_getledstatus(t_akawiiremote *x); +void akawiiremote_getbattery(t_akawiiremote *x); +void akawiiremote_getexpansion(t_akawiiremote *x); +void akawiiremote_getled(t_akawiiremote *x); +void akawiiremote_getaddress(t_akawiiremote *x); +void akawiiremote_getcalibration(t_akawiiremote *x); void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s); void akawiiremote_clock(t_akawiiremote *x); void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); void akawiiremote_free(t_akawiiremote *x); +char remoteStr[] = "remote"; +char nunchukStr[] = "nunchuk"; +char classicStr[] = "classic"; + #ifdef PD void wiiremote_setup() #else /* Max */ @@ -66,6 +78,8 @@ void main() NumVersion outSoftwareVersion; BluetoothHCIVersionInfo outHardwareVersion; + post("aka.wiiremote 1.0B6-UB by Masayuki Akamatsu"); + if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) { if (outSoftwareVersion.majorRev < 1 || outSoftwareVersion.minorAndBugRev < 0x63) @@ -80,8 +94,6 @@ void main() return; } - post("aka.wiiremote 1.0B4-UB by Masayuki Akamatsu"); - #ifdef PD post("\tPd port by Hans-Christoph Steiner"); @@ -95,30 +107,35 @@ void main() class_addbang(wiiremote_class,(t_method)akawiiremote_bang); class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motionsensor"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("irsensor"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getbatterylevel,gensym("getbatterylevel"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansionstatus,gensym("getexpansionstatus"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getledstatus,gensym("getledstatus"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); #else /* Max */ setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); addbang((method)akawiiremote_bang); - addmess((method)akawiiremote_connect,"connect",0); + addmess((method)akawiiremote_address,"address",A_DEFSYM, 0); + addmess((method)akawiiremote_connect,"connect", 0); addmess((method)akawiiremote_disconnect,"disconnect",0); - addmess((method)akawiiremote_motionsensor,"motionsensor", A_DEFLONG, 0); - addmess((method)akawiiremote_irsensor,"irsensor", A_DEFLONG, 0); + addmess((method)akawiiremote_motionsensor,"motion", A_DEFLONG, 0); + addmess((method)akawiiremote_irsensor,"ir", A_DEFLONG, 0); addmess((method)akawiiremote_vibration,"vibration", A_DEFLONG, 0); addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); - - addmess((method)akawiiremote_getbatterylevel,"getbatterylevel",0); - addmess((method)akawiiremote_getexpansionstatus,"getexpansionstatus",0); - addmess((method)akawiiremote_getledstatus,"getledstatus",0); + addmess((method)akawiiremote_expansion,"expansion", A_DEFLONG, 0); + addmess((method)akawiiremote_expansion,"nunchuk", A_DEFLONG, 0); + + addmess((method)akawiiremote_getbattery,"getbattery",0); + addmess((method)akawiiremote_getexpansion,"getexpansion",0); + addmess((method)akawiiremote_getled,"getled",0); + addmess((method)akawiiremote_getaddress,"getaddress",0); + addmess((method)akawiiremote_getcalibration,"getcalibration", 0); addmess((method)akawiiremote_assist,"assist",A_CANT,0); #endif /* PD */ @@ -128,38 +145,114 @@ void main() void akawiiremote_bang(t_akawiiremote *x) { - t_atom list[4]; + t_atom av[5]; if (x->wiiremote->device == nil) return; // do nothing -#ifdef PD - outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); -#else /* Max */ - outlet_int(x->buttonsOut, x->wiiremote->buttonData); -#endif /* PD */ +//#ifdef PD +// outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); +//#else /* Max */ +//#endif /* PD */ + + if (x->wiiremote->isExpansionPortAttached && x->wiiremote->isExpansionPortEnabled) + { + // Classic Controller + if (x->wiiremote->expType == WiiClassicController) + { + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->cButtonData); + outlet_anything(x->dataOut, gensym(classicStr), 2, av); + + // Joystick 1 + SETSYM(av, gensym("stick1")); + SETLONG(av + 1, x->wiiremote->cStickX1); + SETLONG(av + 2, x->wiiremote->cStickY1); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + + // Joystick 2 + SETSYM(av, gensym("stick2")); + SETLONG(av + 1, x->wiiremote->cStickX2); + SETLONG(av + 2, x->wiiremote->cStickY2); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + + // Analog + SETSYM(av, gensym("analog")); + SETLONG(av + 1, x->wiiremote->cAnalogL); + SETLONG(av + 2, x->wiiremote->cAnalogR); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + } + + // Nunchuk + if (x->wiiremote->expType == WiiNunchuk) + { + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->nButtonData); + outlet_anything(x->dataOut, gensym(nunchukStr), 2, av); + + // Joystick + SETSYM(av, gensym("stick")); + SETLONG(av + 1, x->wiiremote->nStickX); + SETLONG(av + 2, x->wiiremote->nStickY); + outlet_anything(x->dataOut, gensym(nunchukStr), 3, av); + + // Motion Sensor + if (x->wiiremote->isMotionSensorEnabled) + { + SETSYM(av, gensym("motion")); + SETLONG(av + 1, x->wiiremote->nAccX); + SETLONG(av + 2, x->wiiremote->nAccY); + SETLONG(av + 3, x->wiiremote->nAccZ); + SETLONG(av + 4, x->wiiremote->nOrientation); + outlet_anything(x->dataOut, gensym(nunchukStr), 5, av); + } + } + } + + // Wii Remote + + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->buttonData); + outlet_anything(x->dataOut, gensym(remoteStr), 2, av); + // IR Sensor if (x->wiiremote->isIRSensorEnabled) { - SETFLOAT(list, x->wiiremote->posX); - SETFLOAT(list + 1, x->wiiremote->posY); - SETFLOAT(list + 2, x->wiiremote->angle); - SETLONG (list + 3, x->wiiremote->tracking); - outlet_list(x->irOut, 0L, 4, list); + SETSYM(av, gensym("ir")); + SETFLOAT(av + 1, x->wiiremote->posX); // posX and posY are "float"???? + SETFLOAT(av + 2, x->wiiremote->posY); + SETFLOAT(av + 3, x->wiiremote->angle); + SETLONG (av + 4, x->wiiremote->tracking); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); } + // Motion Sensor if (x->wiiremote->isMotionSensorEnabled) { - SETLONG(list, x->wiiremote->accX); - SETLONG(list + 1, x->wiiremote->accY); - SETLONG(list + 2, x->wiiremote->accZ); - SETLONG(list + 3, x->wiiremote->orientation); - outlet_list(x->accOut, 0L, 4, list); + SETSYM(av, gensym("motion")); + SETLONG(av + 1, x->wiiremote->accX); + SETLONG(av + 2, x->wiiremote->accY); + SETLONG(av + 3, x->wiiremote->accZ); + SETLONG(av + 4, x->wiiremote->orientation); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); } - - //wiiremote_getstatus(); // stopped in B3 } +//-------------------------------------------------------------------------------------------- + +void akawiiremote_address(t_akawiiremote *x, t_symbol *s) +{ + if (*(s->s_name) == 0) // if null string + *(x->address) = 0; + else + strcpy(x->address, s->s_name); +} + +//-------------------------------------------------------------------------------------------- + void akawiiremote_connect(t_akawiiremote *x) { t_atom status; @@ -172,8 +265,8 @@ void akawiiremote_connect(t_akawiiremote *x) } else { - result = wiiremote_search(x->wiiremote); // start searching the device - x->trial = 0; + result = wiiremote_search(x->wiiremote, x->address); // start searching the device + x->connected = false; clock_unset(x->clock); // stop clock clock_delay(x->clock, 0); // start clock to check the device found } @@ -188,97 +281,208 @@ void akawiiremote_disconnect(t_akawiiremote *x) Boolean result; t_atom status; + clock_unset(x->clock); // stop clock + wiiremote_stopsearch(x->wiiremote); + result = wiiremote_disconnect(x->wiiremote); SETLONG(&status, result); - outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); + outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); + + x->connected = !result; } +//-------------------------------------------------------------------------------------------- + void akawiiremote_motionsensor(t_akawiiremote *x, long enable) { - wiiremote_motionsensor(x->wiiremote, enable); + Boolean result; + t_atom status; + + result = wiiremote_motionsensor(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("motion"), 1, &status); } void akawiiremote_irsensor(t_akawiiremote *x, long enable) { - wiiremote_irsensor(x->wiiremote, enable); + Boolean result; + t_atom status; + + result = wiiremote_irsensor(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("ir"), 1, &status); +} + +void akawiiremote_expansion(t_akawiiremote *x, long enable) +{ + Boolean result; + t_atom status; + + result = wiiremote_expansion(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("nunchuk"), 1, &status); } void akawiiremote_vibration(t_akawiiremote *x, long enable) { - wiiremote_vibration(x->wiiremote, enable); + Boolean result; + t_atom status; + + result = wiiremote_vibration(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("vibration"), 1, &status); } void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) { - wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); + Boolean result; + t_atom status; + + result = wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("led"), 1, &status); } //-------------------------------------------------------------------------------------------- -void akawiiremote_getbatterylevel(t_akawiiremote *x) +void akawiiremote_getbattery(t_akawiiremote *x) { - t_atom status; + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("battery"), 0, nil); + } + else + { + t_atom status; + + SETFLOAT(&status, x->wiiremote->batteryLevel); + outlet_anything(x->statusOut, gensym("battery"), 1, &status); + } +} + +void akawiiremote_getexpansion(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("expansion"), 0, nil); + } + else + { + t_atom status; + if (x->wiiremote->isExpansionPortAttached) + SETLONG(&status, x->wiiremote->expType); + else + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("expansion"), 1, &status); + } +} - SETFLOAT(&status, x->wiiremote->batteryLevel); - outlet_anything(x->statusOut, gensym("batterylevel"), 1, &status); +void akawiiremote_getled(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("led"), 0, nil); + } + else + { + t_atom list[4]; + + SETLONG(list, x->wiiremote->isLED1Illuminated); + SETLONG(list + 1, x->wiiremote->isLED2Illuminated); + SETLONG(list + 2, x->wiiremote->isLED3Illuminated); + SETLONG(list + 3, x->wiiremote->isLED4Illuminated); + outlet_anything(x->statusOut, gensym("led"), 4, list); + } } -void akawiiremote_getexpansionstatus(t_akawiiremote *x) +void akawiiremote_getcalibration(t_akawiiremote *x) { - t_atom status; - - SETLONG(&status, x->wiiremote->isExpansionPortUsed); - outlet_anything(x->statusOut, gensym("expansionstatus"), 1, &status); + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("calibration"), 0, nil); + } + else + { + t_atom list[8]; + + if (x->wiiremote->isExpansionPortAttached) + { + SETSYM(list, gensym(nunchukStr)); + SETSYM(list + 1, gensym("stick")); + SETLONG(list + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); + SETLONG(list + 3, x->wiiremote->nunchukJoyStickCalibData.x_min); + SETLONG(list + 4, x->wiiremote->nunchukJoyStickCalibData.x_center); + SETLONG(list + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); + SETLONG(list + 6, x->wiiremote->nunchukJoyStickCalibData.y_min); + SETLONG(list + 7, x->wiiremote->nunchukJoyStickCalibData.y_center); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + + SETSYM(list + 1, gensym("motion")); + SETLONG(list + 2, x->wiiremote->nunchukCalibData.accX_zero); + SETLONG(list + 3, x->wiiremote->nunchukCalibData.accY_zero); + SETLONG(list + 4, x->wiiremote->nunchukCalibData.accZ_zero); + SETLONG(list + 5, x->wiiremote->nunchukCalibData.accX_1g); + SETLONG(list + 6, x->wiiremote->nunchukCalibData.accY_1g); + SETLONG(list + 7, x->wiiremote->nunchukCalibData.accZ_1g); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + } + + SETSYM(list, gensym(remoteStr)); + SETSYM(list + 1, gensym("motion")); + SETLONG(list + 2, x->wiiremote->wiiCalibData.accX_zero); + SETLONG(list + 3, x->wiiremote->wiiCalibData.accY_zero); + SETLONG(list + 4, x->wiiremote->wiiCalibData.accZ_zero); + SETLONG(list + 5, x->wiiremote->wiiCalibData.accX_1g); + SETLONG(list + 6, x->wiiremote->wiiCalibData.accY_1g); + SETLONG(list + 7, x->wiiremote->wiiCalibData.accZ_1g); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + } } -void akawiiremote_getledstatus(t_akawiiremote *x) +//-------------------------------------------------------------------------------------------- + +void akawiiremote_getaddress(t_akawiiremote *x) { - t_atom list[4]; - - SETLONG(list, x->wiiremote->isLED1Illuminated); - SETLONG(list + 1, x->wiiremote->isLED2Illuminated); - SETLONG(list + 2, x->wiiremote->isLED3Illuminated); - SETLONG(list + 3, x->wiiremote->isLED4Illuminated); - outlet_anything(x->statusOut, gensym("ledstatus"), 4, list); + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("address"), 0, nil); + } + else + { + char str[32]; + t_atom address; + + wiiremote_getaddress(x->wiiremote, str); + SETSYM(&address, gensym(str)); + outlet_anything(x->statusOut, gensym("address"), 1, &address); + } } //-------------------------------------------------------------------------------------------- void akawiiremote_clock(t_akawiiremote *x) { - //Boolean result; + Boolean connection; t_atom status; - if (wiiremote_isconnected(x->wiiremote)) // if the device is connected... + connection = wiiremote_isconnected(x->wiiremote); + + if (x->connected == false && connection == true) // if the device is connected... { - clock_unset(x->clock); // stop clock - - wiiremote_stopsearch(x->wiiremote); - //result = wiiremote_connect(); // remove in B3 - wiiremote_getstatus(x->wiiremote); // add in B3 + wiiremote_getstatus(x->wiiremote); + x->connected = true; SETLONG(&status, 1); outlet_anything(x->statusOut, gensym("connect"), 1, &status); } - else // if the device is not connected... + + if (x->connected == true && connection == false) { - x->trial++; - //SETLONG(&status, x->trial); - //outlet_anything(x->statusOut, gensym("searching"), 1, &status); - - if (x->trial >= kMaxTrial) // if trial is over - { - clock_unset(x->clock); // stop clock - - wiiremote_stopsearch(x->wiiremote); - SETLONG(&status, 0); - outlet_anything(x->statusOut, gensym("connect"), 1, &status); - } - else - { - //post("trial %d",x->trial); - clock_delay(x->clock, x->interval); // restart clock - } + x->connected = false; + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); } + + clock_delay(x->clock, kInterval); // restart clock } //-------------------------------------------------------------------------------------------- @@ -295,10 +499,8 @@ void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) { switch(a) { - case 0: sprintf(s,"list(acc-x acc-y acc-z orientation)"); break; - case 1: sprintf(s,"list(pos-x pos-y angle tracking)"); break; - case 2: sprintf(s,"int(buttons)"); break; - case 3: sprintf(s,"message(status)"); break; + case 0: sprintf(s,"data messages"); break; + case 2: sprintf(s,"status messages"); break; } } } @@ -307,48 +509,55 @@ void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) { -#ifdef PD - t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); - - x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); // add in 1.0B4 - if (x->wiiremote != nil) - wiiremote_init(x->wiiremote); - - x->clock = clock_new(x, (t_method)akawiiremote_clock); - - /* create anything outlet used for HID data */ - x->statusOut = outlet_new(&x->x_obj, 0); - x->buttonsOut = outlet_new(&x->x_obj, &s_float); - x->irOut = outlet_new(&x->x_obj, &s_list); - x->accOut = outlet_new(&x->x_obj, &s_list); -#else /* Max */ t_akawiiremote *x; +#ifdef PD + x = (t_akawiiremote *)pd_new(wiiremote_class); +#else /* Max */ x = (t_akawiiremote *)newobject(akawiiremote_class); +#endif /* PD */ - x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); // add in 1.0B4 + x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); if (x->wiiremote != nil) + { wiiremote_init(x->wiiremote); + x->wiiremote->isMotionSensorEnabled = true; + x->wiiremote->isIRSensorEnabled = false; + x->wiiremote->isVibrationEnabled = false; + x->wiiremote->isExpansionPortEnabled = false; + x->wiiremote->isLED1Illuminated = false; + x->wiiremote->isLED2Illuminated = false; + x->wiiremote->isLED3Illuminated = false; + x->wiiremote->isLED4Illuminated = false; + } x->clock = clock_new(x, (method)akawiiremote_clock); +#ifdef PD + if (ac>0 && av[0].a_type == A_SYMBOL) + strcpy(x->address, av[0].a_w.w_symbol->s_name); + + x->statusOut = outlet_new(&x->x_obj, 0); + x->dataOut = outlet_new(&x->x_obj, 0); +#else /* Max */ + if (ac>0 && av[0].a_type == A_SYM) + strcpy(x->address, av[0].a_w.w_sym->s_name); x->statusOut = outlet_new(x, 0); - x->buttonsOut = intout(x); - x->irOut = listout(x); - x->accOut = listout(x); + x->dataOut = outlet_new(x, 0); #endif /* PD */ - x->trial = 0; - x->interval = kInterval; + x->connected = false; return x; } void akawiiremote_free(t_akawiiremote *x) { - if (x->wiiremote != nil) // add in 1.0B4 + if (x->wiiremote != nil) { - wiiremote_disconnect(x->wiiremote); - freebytes(x->wiiremote, sizeof(WiiRemoteRec)); // add in 1.0B4 + if (wiiremote_isconnected(x->wiiremote)) + wiiremote_disconnect(x->wiiremote); + freebytes(x->wiiremote, sizeof(WiiRemoteRec)); + x->wiiremote = nil; } clock_unset(x->clock); diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c index cabbb6e..2caffb7 100644 --- a/wiiremote/wiiremote.c +++ b/wiiremote/wiiremote.c @@ -9,8 +9,16 @@ typedef unsigned char darr[]; #define kTrial 10 +#define kWait 10000 +// the unit of kWait is microseconds, thus 10000 means 10ms + +#define kWiiIRPixelsWidth 1024.0 +#define kWiiIRPixelsHeight 768.0 + + +Boolean requestUpdates(WiiRemoteRef wiiremote); +void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event); -//static WiiRemoteRec gWiiRemote; // remove in 1.0B4 //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- @@ -22,41 +30,203 @@ void wiiremote_init(WiiRemoteRef wiiremote) wiiremote->ichan = nil; wiiremote->cchan = nil; + wiiremote->address = nil; + wiiremote->accX = 0x10; wiiremote->accY = 0x10; wiiremote->accZ = 0x10; wiiremote->buttonData = 0; + + wiiremote->lowZ = 0; + wiiremote->lowX = 0; wiiremote->leftPoint = -1; wiiremote->tracking = false; wiiremote->batteryLevel = 0; - wiiremote->isIRSensorEnabled = false; + wiiremote->readingRegister = false; wiiremote->isMotionSensorEnabled = false; wiiremote->isVibrationEnabled = false; + wiiremote->isIRSensorEnabled = false; + wiiremote->wiiIRMode = kWiiIRModeExtended; + wiiremote->isExpansionPortEnabled = false; + wiiremote->isExpansionPortAttached = false; + wiiremote->expType = WiiExpNotAttached; - wiiremote->isExpansionPortUsed = false; wiiremote->isLED1Illuminated = false; wiiremote->isLED2Illuminated = false; wiiremote->isLED3Illuminated = false; wiiremote->isLED4Illuminated = false; + + wiiremote->nAccX = 0x10; + wiiremote->nAccY = 0x10; + wiiremote->nAccZ = 0x10; + wiiremote->nButtonData = 0; + + wiiremote->nLowZ = 0; + wiiremote->nLowX = 0; + } //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) +Boolean openCChan(WiiRemoteRef wiiremote) { - CFStringRef myString; + short i; + IOReturn ret; + + // open L2CAPChannel : BluetoothL2CAPPSM = 17 + for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) + { + wiiremote->cchan = nil; + IOBluetoothDeviceCloseConnection(wiiremote->device); + return false; + } + IOBluetoothObjectRetain(wiiremote->cchan); + + return (ret==kIOReturnSuccess); +} - myString = IOBluetoothDeviceGetName(device); - if (myString != nil) +Boolean openIChan(WiiRemoteRef wiiremote) +{ + short i; + IOReturn ret; + + // open L2CAPChannel : BluetoothL2CAPPSM = 19 + for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) { - if (CFStringCompare(myString, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + wiiremote->ichan = nil; + IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); + IOBluetoothObjectRelease(wiiremote->cchan); + IOBluetoothDeviceCloseConnection(wiiremote->device); + return false; + } + IOBluetoothObjectRetain(wiiremote->ichan); + + return (ret==kIOReturnSuccess); +} + +//-------------------------------------------------------------------------------------------- + +Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, unsigned short length) +{ + unsigned char buf[40]; + IOReturn ret; + int i; + + memset(buf,0,40); + buf[0] = 0x52; + memcpy(buf+1, data, length); + if (buf[1] == 0x16) + length=23; + else + length++; + + usleep(kWait); // wait 10ms // Done to make sure commands don't happen too fast. + + for (i = 0; icchan, buf, length); + if (ret == kIOReturnSuccess) + break; + usleep(kWait); + } + + if (ret != kIOReturnSuccess) + wiiremote_disconnect(wiiremote); + + return (ret==kIOReturnSuccess); +} + +Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, unsigned short length) +{ + unsigned char cmd[22]; + int i; + unsigned long addr = address; + + + for(i=0 ; i>24) & 0xFF; + cmd[2] = (addr>>16) & 0xFF; + cmd[3] = (addr>> 8) & 0xFF; + cmd[4] = (addr>> 0) & 0xFF; + cmd[5] = length; + + // and of course the vibration flag, as usual + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + + data = cmd; + + return sendCommand(wiiremote, cmd, 22); +} + +Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short length) +{ + + unsigned char cmd[7]; + unsigned long addr = address; + unsigned short len = length; + + cmd[0] = 0x17; + cmd[1] = (addr>>24)&0xFF; + cmd[2] = (addr>>16)&0xFF; + cmd[3] = (addr>> 8)&0xFF; + cmd[4] = (addr>> 0)&0xFF; + + cmd[5] = (len >> 8)&0xFF; + cmd[6] = (len >> 0)&0xFF; + + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (cmd[1] & 0x02) wiiremote->readingRegister = true; + + return sendCommand(wiiremote, cmd, 7); +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) +{ + CFStringRef name; + CFStringRef address; + + if (wiiremote_isconnected(wiiremote)) + return; + + name = IOBluetoothDeviceGetName(device); + address = IOBluetoothDeviceGetAddressString(device); + if (name != nil && address != nil) + { + if (CFStringCompare(name, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) { - wiiremote->device = IOBluetoothObjectRetain(device); - if ( !wiiremote_connect(wiiremote)) // add in B3 - wiiremote_disconnect(wiiremote); // add in B3 + if ( CFStringGetLength(wiiremote->address) == 0 + || CFStringCompare(address, wiiremote->address, kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + wiiremote->device = IOBluetoothObjectRetain(device); + if ( wiiremote_connect(wiiremote) == false ) + wiiremote_disconnect(wiiremote); + } } } } @@ -73,12 +243,23 @@ void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoot void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) { + IOReturn ret; + if (aborted) return; // called by stop ;) if (error != kIOReturnSuccess) + { + wiiremote_stopsearch((WiiRemoteRef)refCon); + return; + } + + /* + ret = IOBluetoothDeviceInquiryStart(((WiiRemoteRef)refCon)->inquiry); + if (ret != kIOReturnSuccess) { wiiremote_stopsearch((WiiRemoteRef)refCon); } + */ } //-------------------------------------------------------------------------------------------- @@ -91,7 +272,7 @@ Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) return result; } -Boolean wiiremote_search(WiiRemoteRef wiiremote) +Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) { IOReturn ret; @@ -102,6 +283,10 @@ Boolean wiiremote_search(WiiRemoteRef wiiremote) IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); IOBluetoothDeviceInquirySetCompleteCallback(wiiremote->inquiry, myCompleteFunc); + + if (wiiremote->address != nil) + CFRelease(wiiremote->address); + wiiremote->address = CFStringCreateWithCString(nil, address, kCFStringEncodingMacRoman); ret = IOBluetoothDeviceInquiryStart(wiiremote->inquiry); if (ret != kIOReturnSuccess) @@ -138,125 +323,414 @@ Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- - void myDataListener(IOBluetoothL2CAPChannelRef channel, void *data, UInt16 length, void *refCon) +unsigned char decrypt(unsigned char data) { - WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; - unsigned char *dp = (unsigned char*)data; + return (data ^ 0x17) + 0x17; +} - if (dp[1] == 0x20 && length >= 8) +//-------------------------------------------------------------------------------------------- + +/** +* Handle report 0x21 (Read Data) from wiimote. + * dp[0] = Bluetooth header + * dp[1] = (0x21) Report/Channel ID + * dp[2] = Wiimote Buttons + * dp[3] = Wiimote Buttons + * dp[4] = High 4 bits = payload size; Low 4 bits = Error flag (0 = all good) + * dp[5] = Offset of memory read + * dp[6] = Offset of memory read + * dp[7+] = the Data. + **/ + +void handleRAMData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + // specify attached expasion device + if ((dp[5] == 0x00) && (dp[6] == 0xF0)) { - wiiremote->batteryLevel = (double)dp[7]; - wiiremote->batteryLevel /= (double)0xC0; - - wiiremote->isExpansionPortUsed = (dp[4] & 0x02) != 0; - wiiremote->isLED1Illuminated = (dp[4] & 0x10) != 0; - wiiremote->isLED2Illuminated = (dp[4] & 0x20) != 0; - wiiremote->isLED3Illuminated = (dp[4] & 0x40) != 0; - wiiremote->isLED4Illuminated = (dp[4] & 0x80) != 0; - - //have to reset settings (vibration, motion, IR and so on...) - wiiremote_irsensor(wiiremote, wiiremote->isIRSensorEnabled); + if (decrypt(dp[21]) == 0x00) + { + wiiremote->expType = WiiNunchuk; + } + else + if (decrypt(dp[21]) == 0x01) + { + wiiremote->expType = WiiClassicController; + } + else + { + wiiremote->expType = WiiExpNotAttached; + } + // initExpPort = NO; + return; } + + // wiimote calibration data + if (!wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) + { + wiiremote->wiiCalibData.accX_zero = dp[7]; + wiiremote->wiiCalibData.accY_zero = dp[8]; + wiiremote->wiiCalibData.accZ_zero = dp[9]; + + //dp[10] - unknown/unused + + wiiremote->wiiCalibData.accX_1g = dp[11]; + wiiremote->wiiCalibData.accY_1g = dp[12]; + wiiremote->wiiCalibData.accZ_1g = dp[13]; + return; + } + + // expansion device calibration data. + if (wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) + { + if (wiiremote->expType == WiiNunchuk) + { + //nunchuk calibration data + wiiremote->nunchukCalibData.accX_zero = decrypt(dp[7]); + wiiremote->nunchukCalibData.accY_zero = decrypt(dp[8]); + wiiremote->nunchukCalibData.accZ_zero = decrypt(dp[9]); + + wiiremote->nunchukCalibData.accX_1g = decrypt(dp[11]); + wiiremote->nunchukCalibData.accY_1g = decrypt(dp[12]); + wiiremote->nunchukCalibData.accZ_1g = decrypt(dp[13]); + + wiiremote->nunchukJoyStickCalibData.x_max = decrypt(dp[15]); + wiiremote->nunchukJoyStickCalibData.x_min = decrypt(dp[16]); + wiiremote->nunchukJoyStickCalibData.x_center = decrypt(dp[17]); + + wiiremote->nunchukJoyStickCalibData.y_max = decrypt(dp[18]); + wiiremote->nunchukJoyStickCalibData.y_min = decrypt(dp[19]); + wiiremote->nunchukJoyStickCalibData.y_center = decrypt(dp[20]); + + return; + } + else + if (wiiremote->expType == WiiClassicController) + { + //classic controller calibration data (probably) + } + } + + // wii remote buttons + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; +} + +void handleStatusReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + wiiremote->batteryLevel = (double)dp[7]; + wiiremote->batteryLevel /= (double)0xC0; // C0 = fully charged. + + if ((dp[4] & 0x02)) //some device attached to Wiimote + { + wiiremote->isExpansionPortAttached = true; + // initExpPort = YES; + + Boolean ret = writeData(wiiremote, (darr){0x00}, 0x04A40040, 1); // Initialize the device + + if (ret == false) + { + wiiremote->isExpansionPortAttached = false; + return; + } + + usleep(kWait); // Give the write a chance to be processed. + + ret = readData(wiiremote, 0x04A400F0, 16); // read expansion device type + if (ret == false) + { + wiiremote->isExpansionPortAttached = false; + } + } + else + { // unplugged + wiiremote->isExpansionPortAttached = false; + wiiremote->expType = WiiExpNotAttached; + } + + if (dp[4] & 0x10) + wiiremote->isLED1Illuminated = true; + else + wiiremote->isLED1Illuminated = false; + + if (dp[4] & 0x20) + wiiremote->isLED2Illuminated = true; + else + wiiremote->isLED2Illuminated = false; + + if (dp[4] & 0x40) + wiiremote->isLED3Illuminated = true; + else + wiiremote->isLED3Illuminated = false; + + if (dp[4] & 0x80) + wiiremote->isLED4Illuminated = true; + else + wiiremote->isLED4Illuminated = false; +} - if ((dp[1]&0xF0) == 0x30) +void handleExtensionData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + unsigned char startByte; + + switch (dp[1]) { + case 0x34 : + startByte = 4; + break; + case 0x35 : + startByte = 7; + break; + case 0x36 : + startByte = 14; + break; + case 0x37 : + startByte = 17; + break; + default: + return; // This shouldn't ever happen. + break; + } + + if (wiiremote->expType == WiiNunchuk) { - wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; - - if (dp[1] & 0x01) + wiiremote->nStickX = decrypt(dp[startByte]); + wiiremote->nStickY = decrypt(dp[startByte +1]); + wiiremote->nAccX = decrypt(dp[startByte +2]); + wiiremote->nAccY = decrypt(dp[startByte +3]); + wiiremote->nAccZ = decrypt(dp[startByte +4]); + wiiremote->nButtonData = decrypt(dp[startByte +5]); + + wiiremote->nLowZ = wiiremote->nLowZ * .9 + wiiremote->nAccZ * .1; + wiiremote->nLowX = wiiremote->nLowX * .9 + wiiremote->nAccX * .1; + + float absx = abs(wiiremote->nLowX - 128); + float absz = abs(wiiremote->nLowZ - 128); + + if (wiiremote->nOrientation == 0 || wiiremote->nOrientation == 2) absx -= 5; + if (wiiremote->nOrientation == 1 || wiiremote->nOrientation == 3) absz -= 5; + + if (absz >= absx) { - wiiremote->accX = dp[4]; - wiiremote->accY = dp[5]; - wiiremote->accZ = dp[6]; - - wiiremote->lowZ = wiiremote->lowZ * .9 + wiiremote->accZ * .1; - wiiremote->lowX = wiiremote->lowX * .9 + wiiremote->accX * .1; - - float absx = abs(wiiremote->lowX - 128); - float absz = abs(wiiremote->lowZ - 128); - - if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; - if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; - - if (absz >= absx) - { - if (absz > 5) - wiiremote->orientation = (wiiremote->lowZ > 128) ? 0 : 2; - } - else - { - if (absx > 5) - wiiremote->orientation = (wiiremote->lowX > 128) ? 3 : 1; - } - //printf("orientation: %d\n", orientation); + if (absz > 5) + wiiremote->nOrientation = (wiiremote->nLowZ > 128) ? 0 : 2; } - - if (dp[1] & 0x02) + else { - int i; - for(i=0 ; i<4 ; i++) - { - wiiremote->irData[i].x = dp[7 + 3*i]; - wiiremote->irData[i].y = dp[8 + 3*i]; - wiiremote->irData[i].s = dp[9 + 3*i]; - wiiremote->irData[i].x += (wiiremote->irData[i].s & 0x30) << 4; - wiiremote->irData[i].y += (wiiremote->irData[i].s & 0xC0) << 2; - wiiremote->irData[i].s &= 0x0F; - } + if (absx > 5) + wiiremote->nOrientation = (wiiremote->nLowX > 128) ? 3 : 1; } } + else + if (wiiremote->expType == WiiClassicController) + { + wiiremote->cButtonData = (unsigned short)(decrypt(dp[startByte + 4]) << 8) + decrypt(dp[startByte + 5]); + wiiremote->cButtonData = ~wiiremote->cButtonData; // bit reverse + + wiiremote->cStickX1 = decrypt(dp[startByte]) & 0x3F; + wiiremote->cStickY1 = decrypt(dp[startByte + 1]) & 0x3F; - float ox, oy; + wiiremote->cStickX2 = (((decrypt(dp[startByte +0]) & 0xC0) >> 3) | + ((decrypt(dp[startByte +1]) & 0xC0) >> 5) | + ((decrypt(dp[startByte +2]) & 0x80) >> 7)) & 0x1F; + wiiremote->cStickY2 = decrypt(dp[startByte + 2]) & 0x1F; + + wiiremote->cAnalogL = (((decrypt(dp[startByte +2]) & 0x60) >> 2) | + ((decrypt(dp[startByte +3]) & 0xE0) >> 5)) & 0x1F; + wiiremote->cAnalogR = decrypt(dp[startByte + 3]) & 0x1F; + } +} - if (wiiremote->irData[0].s < 0x0F && wiiremote->irData[1].s < 0x0F) +void handleIRData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + int i; + + if (dp[1] == 0x33) + { // 12 IR bytes + int startByte = 0; + for(i=0 ; i < 4 ; i++) + { + startByte = 7 + 3 * i; + wiiremote->irData[i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; + wiiremote->irData[i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; + wiiremote->irData[i].s = dp[startByte +2] & 0x0F; + } + } + else + { // 10 IR bytes + int shift = (dp[1] == 0x36) ? 4 : 7; + int startByte = 0; + for (i=0; i < 2; i++) { + startByte = shift + 5 * i; + wiiremote->irData[2*i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; + wiiremote->irData[2*i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; + wiiremote->irData[2*i].s = ((wiiremote->irData[2*i].x == wiiremote->irData[2*i].y) && (wiiremote->irData[2*i].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. + + wiiremote->irData[(2*i)+1].x = (dp[startByte +3] | ((dp[startByte +2] & 0x03) << 8)) & 0x3FF; + wiiremote->irData[(2*i)+1].y = (dp[startByte +4] | ((dp[startByte +2] & 0x0C) << 6)) & 0x3FF; + wiiremote->irData[(2*i)+1].s = ((wiiremote->irData[(2*i)+1].x == wiiremote->irData[(2*i)+1].y) && (wiiremote->irData[(2*i)+1].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. + } + } + + int p1 = -1; + int p2 = -1; + // we should modify this loop to take the points with the lowest s (the brightest ones) + for (i=0 ; i<4 ; i++) { + if (p1 == -1) { + if (wiiremote->irData [i].s < 0x0F) + p1 = i; + } else { + if (wiiremote->irData [i].s < 0x0F) { + p2 = i; + break; + } + } + } + + double ox, oy; + if ((p1 > -1) && (p2 > -1)) { - int l = wiiremote->leftPoint, r; + int l = wiiremote->leftPoint; if (wiiremote->leftPoint == -1) { - // printf("Tracking.\n"); switch (wiiremote->orientation) { - case 0: l = (wiiremote->irData[0].x < wiiremote->irData[1].x) ? 0 : 1; break; - case 1: l = (wiiremote->irData[0].y > wiiremote->irData[1].y) ? 0 : 1; break; - case 2: l = (wiiremote->irData[0].x > wiiremote->irData[1].x) ? 0 : 1; break; - case 3: l = (wiiremote->irData[0].y < wiiremote->irData[1].y) ? 0 : 1; break; + case 0: l = (wiiremote->irData[p1].x < wiiremote->irData[p2].x) ? 0 : 1; break; + case 1: l = (wiiremote->irData[p1].y > wiiremote->irData[p2].y) ? 0 : 1; break; + case 2: l = (wiiremote->irData[p1].x > wiiremote->irData[p2].x) ? 0 : 1; break; + case 3: l = (wiiremote->irData[p1].y < wiiremote->irData[p2].y) ? 0 : 1; break; } + wiiremote->leftPoint = l; } - r = 1-l; - - float dx = wiiremote->irData[r].x - wiiremote->irData[l].x; - float dy = wiiremote->irData[r].y - wiiremote->irData[l].y; - - float d = sqrt(dx*dx+dy*dy); - + int r = 1-l; + + double dx = wiiremote->irData[r].x - wiiremote->irData[l].x; + double dy = wiiremote->irData[r].y - wiiremote->irData[l].y; + double d = hypot (dx, dy); + dx /= d; dy /= d; - - float cx = (wiiremote->irData[l].x+wiiremote->irData[r].x)/1024.0 - 1; - float cy = (wiiremote->irData[l].y+wiiremote->irData[r].y)/1024.0 - .75; - - wiiremote->angle = atan2(dy, dx); - + + double cx = (wiiremote->irData[l].x + wiiremote->irData[r].x)/kWiiIRPixelsWidth - 1; + double cy = (wiiremote->irData[l].y + wiiremote->irData[r].y)/kWiiIRPixelsHeight - 1; + ox = -dy*cy-dx*cx; oy = -dx*cy+dy*cx; - //printf("x:%5.2f; y: %5.2f; angle: %5.1f\n", ox, oy, angle*180/M_PI); + // cam: + // Compensate for distance. There must be fewer than 0.75*768 pixels between the spots for this to work. + // In other words, you have to be far enough away from the sensor bar for the two spots to have enough + // space on the image sensor to travel without one of the points going off the image. + // note: it is working very well ... + double gain = 4; + if (d < (0.75 * kWiiIRPixelsHeight)) + gain = 1 / (1 - d/kWiiIRPixelsHeight); + + ox *= gain; + oy *= gain; + + wiiremote->angle = atan2(dy, dx); wiiremote->tracking = true; } else { - // printf("Not tracking.\n"); ox = oy = -100; + wiiremote->leftPoint = -1; // not tracking wiiremote->angle = -100; - wiiremote->leftPoint = -1; wiiremote->tracking = false; } - + wiiremote->posX = ox; wiiremote->posY = oy; } +void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + // wiimote buttons + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; + + // report contains extension data + switch (dp[1]) + { + case 0x34 : + case 0x35 : + case 0x36 : + case 0x37 : + handleExtensionData(wiiremote, dp, dataLength); + break; + } + + // report contains IR data + if (dp[1] & 0x02) + { + handleIRData(wiiremote, dp, dataLength); + } + + // report contains motion sensor data + if (dp[1] & 0x01) + { + wiiremote->accX = dp[4]; + wiiremote->accY = dp[5]; + wiiremote->accZ = dp[6]; + + wiiremote->lowZ = wiiremote->lowZ * 0.9 + wiiremote->accZ * 0.1; + wiiremote->lowX = wiiremote->lowX * 0.9 + wiiremote->accX * 0.1; + + float absx = abs(wiiremote->lowX-128); + float absz = abs(wiiremote->lowZ-128); + + if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; + if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; + + if (absz >= absx) + { + if (absz > 5) + wiiremote->orientation = (wiiremote->lowZ > 128)?0:2; + } + else + { + if (absx > 5) + wiiremote->orientation = (wiiremote->lowX > 128)?3:1; + } + } +} + +//-------------------------------------------------------------------------------------------- + + void myDataListener(IOBluetoothL2CAPChannelRef channel, void *dataPointer, UInt16 dataLength, void *refCon) +{ + WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; + unsigned char* dp = (unsigned char*)dataPointer; + + if (!wiiremote->device) + return; + + //controller status (expansion port and battery level data) - received when report 0x15 sent to Wiimote (getCurrentStatus:) or status of expansion port changes. + if (dp[1] == 0x20 && dataLength >= 8) + { + handleStatusReport(wiiremote, dp, dataLength); + requestUpdates(wiiremote); // Make sure we keep getting state change reports. + return; + } + + if (dp[1] == 0x21) + { + handleRAMData(wiiremote, dp, dataLength); + return; + } + + if (dp[1] == 0x22) + { // Write data response + //NSLog(@"Write data response: %00x %00x %00x %00x", dp[2], dp[3], dp[4], dp[5]); + return; + } + + // report contains button info + if ((dp[1] & 0xF0) == 0x30) + { + handleButtonReport(wiiremote, dp, dataLength); + } +} + void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) { if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) @@ -277,7 +751,34 @@ void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoo void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) { - //wiiremote_disconnect(); + CFStringRef itsAddress, myAddress; + + itsAddress = IOBluetoothDeviceGetAddressString(objectRef); + if (itsAddress != nil) + { + myAddress = IOBluetoothDeviceGetAddressString(((WiiRemoteRef)refCon)->device); + if (myAddress != nil) + { + if (CFStringCompare(itsAddress, myAddress, 0) == kCFCompareEqualTo) + { + wiiremote_disconnect((WiiRemoteRef)refCon); + } + CFRelease(myAddress); + } + CFRelease(itsAddress); + } +} + +//-------------------------------------------------------------------------------------------- + +void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address) +{ + CFStringRef cfstring; + + cfstring = IOBluetoothDeviceGetAddressString(wiiremote->device); + CFStringGetCString(cfstring, address, 32, kCFStringEncodingMacRoman); + CFRelease(cfstring); + } //-------------------------------------------------------------------------------------------- @@ -285,6 +786,7 @@ void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOB Boolean wiiremote_connect(WiiRemoteRef wiiremote) { IOReturn ret; + Boolean result; short i; if (wiiremote->device == nil) @@ -296,12 +798,12 @@ Boolean wiiremote_connect(WiiRemoteRef wiiremote) ret = IOBluetoothDeviceOpenConnection(wiiremote->device, nil, nil); if ( ret == kIOReturnSuccess) break; - usleep(10000); // wait 10ms + usleep(kWait); // wait 10ms } if (i==kTrial) return false; - wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, 0); + wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, (void *)wiiremote); // performs an SDP query for (i=0; idevice, nil, nil); if ( ret == kIOReturnSuccess) break; - usleep(10000); // wait 10ms + usleep(kWait); // wait 10ms } if (i==kTrial) return false; + + result = openCChan(wiiremote); + result = openIChan(wiiremote); - // open L2CAPChannel : BluetoothL2CAPPSM = 17 - for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); - if ( ret == kIOReturnSuccess) - break; - usleep(10000); // wait 10ms - } - if (i==kTrial) + if (result) { - wiiremote->cchan = nil; - IOBluetoothDeviceCloseConnection(wiiremote->device); - wiiremote->device = nil; - return false; + result = wiiremote_led(wiiremote, wiiremote->isLED1Illuminated, wiiremote->isLED2Illuminated, wiiremote->isLED3Illuminated, wiiremote->isLED4Illuminated); } - // open L2CAPChannel : BluetoothL2CAPPSM = 19 - for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); - if ( ret == kIOReturnSuccess) - break; - usleep(10000); // wait 10ms + wiiremote_disconnect(wiiremote); + return result; } - if (i==kTrial) - { - wiiremote->ichan = nil; - IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); - IOBluetoothDeviceCloseConnection(wiiremote->device); - wiiremote->device = nil; - return false; - } - - wiiremote_motionsensor(wiiremote, true); - wiiremote_irsensor(wiiremote, false); - wiiremote_vibration(wiiremote, false); - wiiremote_led(wiiremote, false, false, false, false); + + wiiremote_getstatus(wiiremote); + requestUpdates(wiiremote); + + readData(wiiremote, 0x0020, 7); // Get Accelerometer callibration data return true; } @@ -358,56 +841,58 @@ Boolean wiiremote_connect(WiiRemoteRef wiiremote) Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) { - short i; - - if (wiiremote->disconnectNotification != nil) - { - IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); - wiiremote->disconnectNotification = nil; - } - - if (wiiremote->cchan && IOBluetoothDeviceIsConnected(wiiremote->device)) + short i; + + if (wiiremote->cchan) { - for (i=0; idevice)) { - if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan) == kIOReturnSuccess) + for (i=0; icchan = nil; - break; + if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan) == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms } } if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->cchan); + wiiremote->cchan = nil; } - if (wiiremote->ichan && IOBluetoothDeviceIsConnected(wiiremote->device)) + if (wiiremote->ichan) { - for (i=0; idevice)) { - if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->ichan) == kIOReturnSuccess) + for (i=0; iichan = nil; - break; + if (IOBluetoothL2CAPChannelCloseChannel(wiiremote->ichan) == kIOReturnSuccess) + break; } } if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->ichan); + wiiremote->ichan = nil; } - if (wiiremote->device && IOBluetoothDeviceIsConnected(wiiremote->device)) + if (wiiremote->device) { - for (i=0; idevice)) { - if (IOBluetoothDeviceCloseConnection(wiiremote->device) == kIOReturnSuccess) + for (i=0; idevice) == kIOReturnSuccess) + break; } } if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->device); + wiiremote->device = nil; } - if (wiiremote->device != nil) + if (wiiremote->disconnectNotification != nil) { - IOBluetoothObjectRelease(wiiremote->device); - wiiremote->device = nil; + IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); + wiiremote->disconnectNotification = nil; } return true; @@ -416,53 +901,77 @@ Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- -Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, size_t length) -{ - unsigned char buf[40]; - IOReturn ret; - int i; +Boolean requestUpdates(WiiRemoteRef wiiremote) +{ + Boolean result; - memset(buf,0,40); - buf[0] = 0x52; - memcpy(buf+1, data, length); - if (buf[1] == 0x16) - length=23; - else - length++; + // Set the report type the Wiimote should send. + unsigned char cmd[] = {0x12, 0x02, 0x30}; // Just buttons. - for (i = 0; icchan, buf, length); - if (ret == kIOReturnSuccess) - break; - usleep(10000); - } + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - return (ret==kIOReturnSuccess); -} - -Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, size_t length) -{ - unsigned char cmd[22]; - unsigned int i; - - for(i=0 ; iisIRSensorEnabled) + { + if (wiiremote->isExpansionPortEnabled) + { + cmd[2] = 0x36; // Buttons, 10 IR Bytes, 9 Extension Bytes + wiiremote->wiiIRMode = kWiiIRModeBasic; + } + else + { + cmd[2] = 0x33; // Buttons, Accelerometer, and 12 IR Bytes. + wiiremote->wiiIRMode = kWiiIRModeExtended; + } + + // Set IR Mode + writeData(wiiremote, (darr){ wiiremote->wiiIRMode }, 0x04B00033, 1); + usleep(kWait); // wait 10ms + } + else + { + if (wiiremote->isExpansionPortEnabled) + { + cmd[2] = 0x34; // Buttons, 19 Extension Bytes + } + else + { + cmd[2] = 0x30; // Buttons + } + } - cmd[0] = 0x16; - cmd[1] = (address>>24) & 0xFF; - cmd[2] = (address>>16) & 0xFF; - cmd[3] = (address>> 8) & 0xFF; - cmd[4] = (address>> 0) & 0xFF; - cmd[5] = length; - - // and of course the vibration flag, as usual - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; // Add Accelerometer - data = cmd; + usleep(kWait); // wait 10ms + result = sendCommand(wiiremote, cmd, 3); - return sendCommand(wiiremote, cmd, 22); + return(result); } //-------------------------------------------------------------------------------------------- @@ -470,74 +979,14 @@ Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned lo Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled) { wiiremote->isMotionSensorEnabled = enabled; - - unsigned char cmd[] = {0x12, 0x00, 0x30}; - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; - if (wiiremote->isIRSensorEnabled) cmd[2] |= 0x02; - - return sendCommand(wiiremote, cmd, 3); -} - -Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) -{ - IOReturn ret; - - wiiremote->isIRSensorEnabled = enabled; - - // set register 0x12 (report type) - if (ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled) == false) return ret; - - // set register 0x13 (ir enable/vibe) - if (ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled) == false) return ret; - - // set register 0x1a (ir enable 2) - unsigned char cmd[] = {0x1a, 0x00}; - if (enabled) cmd[1] |= 0x04; - if (ret = sendCommand(wiiremote, cmd, 2) == false) return ret; - - if(enabled){ - // based on marcan's method, found on wiili wiki: - // tweaked to include some aspects of cliff's setup procedure in the hopes - // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) - // the sleeps help it it seems - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x90}, 0x04B00006, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0xC0}, 0x04B00008, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x40}, 0x04B0001A, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x33}, 0x04B00033, 1) == false) return ret; - usleep(10000); - if (ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1) == false) return ret; - - }else{ - // probably should do some writes to power down the camera, save battery - // but don't know how yet. - - //bug fix #1614587 - wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); - wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); - } - - return true; + return requestUpdates(wiiremote); } Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled) { wiiremote->isVibrationEnabled = enabled; - - unsigned char cmd[] = {0x13, 0x00}; - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; - - return sendCommand(wiiremote, cmd, 2);; + return requestUpdates(wiiremote); } Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) @@ -557,6 +1006,73 @@ Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2 return sendCommand(wiiremote, cmd, 2); } +Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled) +{ + wiiremote->isExpansionPortEnabled = enabled; + if (wiiremote->isExpansionPortAttached == false) + { + wiiremote->isExpansionPortEnabled = false; + } + else + { + readData(wiiremote, 0x04A40020, 16); //get calbdata + } + + return requestUpdates(wiiremote); +} + +Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) +{ + Boolean ret; + + wiiremote->isIRSensorEnabled = enabled; + + // ir enable 1 + unsigned char cmd[] = {0x13, 0x00}; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; + if ((ret = sendCommand(wiiremote, cmd, 2)) == false) + return ret; + usleep(kWait); + + // set register 0x1a (ir enable 2) + unsigned char cmd2[] = {0x1a, 0x00}; + if (enabled) cmd2[1] |= 0x04; + if ((ret = sendCommand(wiiremote, cmd2, 2)) == false) + return ret; + usleep(kWait); + + if(enabled) + { + // based on marcan's method, found on wiili wiki: + // tweaked to include some aspects of cliff's setup procedure in the hopes + // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) + // the sleeps help it it seems + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xC0}, 0x04B00000, 9)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x40, 0x00}, 0x04B0001A, 2)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1)) == false) return ret; + usleep(kWait); + + requestUpdates(wiiremote); + } + else + { + // probably should do some writes to power down the camera, save battery + // but don't know how yet. + + ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); + ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); + ret = wiiremote_expansion(wiiremote, wiiremote->isExpansionPortEnabled); + } + + return ret; +} + Boolean wiiremote_getstatus(WiiRemoteRef wiiremote) { unsigned char cmd[] = {0x15, 0x00}; diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h index 66ec4ac..f8ad39d 100644 --- a/wiiremote/wiiremote.h +++ b/wiiremote/wiiremote.h @@ -8,16 +8,96 @@ #include #include +// Macros for PD for compability with Max macros +#ifdef PD +#define SETSYM SETSYMBOL +#define SETLONG SETFLOAT +#endif + +typedef unsigned char WiiIRModeType; +enum { + kWiiIRModeBasic = 0x01, + kWiiIRModeExtended = 0x03, + kWiiIRModeFull = 0x05 +}; + typedef struct { int x, y, s; } IRData; +typedef struct { + unsigned char accX_zero, accY_zero, accZ_zero, accX_1g, accY_1g, accZ_1g; +} WiiAccCalibData; + +typedef struct { + unsigned char x_min, x_max, x_center, y_min, y_max, y_center; +} WiiJoyStickCalibData; + +typedef UInt16 WiiButtonType; +enum { + WiiRemoteAButton, + WiiRemoteBButton, + WiiRemoteOneButton, + WiiRemoteTwoButton, + WiiRemoteMinusButton, + WiiRemoteHomeButton, + WiiRemotePlusButton, + WiiRemoteUpButton, + WiiRemoteDownButton, + WiiRemoteLeftButton, + WiiRemoteRightButton, + + WiiNunchukZButton, + WiiNunchukCButton, + + WiiClassicControllerXButton, + WiiClassicControllerYButton, + WiiClassicControllerAButton, + WiiClassicControllerBButton, + WiiClassicControllerLButton, + WiiClassicControllerRButton, + WiiClassicControllerZLButton, + WiiClassicControllerZRButton, + WiiClassicControllerUpButton, + WiiClassicControllerDownButton, + WiiClassicControllerLeftButton, + WiiClassicControllerRightButton, + WiiClassicControllerMinusButton, + WiiClassicControllerHomeButton, + WiiClassicControllerPlusButton +}; + + +typedef UInt16 WiiExpansionPortType; +enum{ + WiiExpNotAttached, + WiiNunchuk, + WiiClassicController +}; + +typedef UInt16 WiiAccelerationSensorType; +enum{ + WiiRemoteAccelerationSensor, + WiiNunchukAccelerationSensor +}; + + +typedef UInt16 WiiJoyStickType; +enum{ + WiiNunchukJoyStick, + WiiClassicControllerLeftJoyStick, + WiiClassicControllerRightJoyStick +}; + + typedef struct _WiiRemoteRec { IOBluetoothDeviceInquiryRef inquiry; IOBluetoothDeviceRef device; IOBluetoothL2CAPChannelRef ichan; IOBluetoothL2CAPChannelRef cchan; + + CFStringRef address; unsigned char accX; unsigned char accY; @@ -28,35 +108,68 @@ typedef struct _WiiRemoteRec float lowX; int orientation; int leftPoint; // is point 0 or 1 on the left. -1 when not tracking. + float posX; float posY; float angle; Boolean tracking; - + + WiiExpansionPortType expType; + WiiAccCalibData wiiCalibData, nunchukCalibData; + WiiJoyStickCalibData nunchukJoyStickCalibData; + WiiIRModeType wiiIRMode; IRData irData[4]; double batteryLevel; - Boolean isIRSensorEnabled; + Boolean readingRegister; Boolean isMotionSensorEnabled; + Boolean isIRSensorEnabled; Boolean isVibrationEnabled; - - Boolean isExpansionPortUsed; + Boolean isExpansionPortEnabled; + Boolean initExpPort; Boolean isLED1Illuminated; Boolean isLED2Illuminated; Boolean isLED3Illuminated; Boolean isLED4Illuminated; + Boolean isExpansionPortAttached; + IOBluetoothUserNotificationRef disconnectNotification; + + //nunchuk + unsigned char nStickX; + unsigned char nStickY; + unsigned char nAccX; + unsigned char nAccY; + unsigned char nAccZ; + unsigned char nButtonData; + + float nLowZ; + float nLowX; + int nOrientation; + + //classic controller + unsigned short cButtonData; + unsigned char cStickX1; + unsigned char cStickY1; + unsigned char cStickX2; + unsigned char cStickY2; + unsigned char cAnalogL; + unsigned char cAnalogR; + } WiiRemoteRec, *WiiRemoteRef; void wiiremote_init(WiiRemoteRef wiiremote); Boolean wiiremote_isconnected(WiiRemoteRef wiiremote); -Boolean wiiremote_search(WiiRemoteRef wiiremote); +Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address); Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote); Boolean wiiremote_connect(WiiRemoteRef wiiremote); Boolean wiiremote_disconnect(WiiRemoteRef wiiremote); +void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address); Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); +Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled); Boolean wiiremote_getstatus(WiiRemoteRef wiiremote); + -- cgit v1.2.1 From 71d377c64cf05eb5726e4ec803dc8288bf4c8357 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 7 Mar 2008 18:47:45 +0000 Subject: A first step of success, I got the wiiremote successfully connecting and getting one data event into Pd with the first bang. Now I have to figure out how to run the Carbon CFRunLoop into Pd land. - cleaned up some unused variables - fixed some warnings - folded in the b7 version - cleaned up the port a bit This code directly compiles and works fine on Max/MSP. svn path=/trunk/externals/io/; revision=9543 --- wiiremote/TODO | 7 +++ wiiremote/aka.wiiremote.c | 136 +++++++++++++++++++++++++++++++++----------- wiiremote/wiiremote-help.pd | 96 ++++++++++++++++++++++--------- wiiremote/wiiremote.c | 31 +++++----- wiiremote/wiiremote.h | 2 +- 5 files changed, 199 insertions(+), 73 deletions(-) create mode 100644 wiiremote/TODO diff --git a/wiiremote/TODO b/wiiremote/TODO new file mode 100644 index 0000000..a8da43d --- /dev/null +++ b/wiiremote/TODO @@ -0,0 +1,7 @@ + + + - try out IOBluetoothLocalDeviceAvailable(wiiremote->inquiry); to see if that will set up the event loops (http://lists.apple.com/archives/bluetooth-dev/2006/Dec/msg00001.html) + + +- try CFRunLoopRun(); then CFRunLoopStop(CFRunLoopGetCurrent()); in akawiiremote_clock() and akawiiremote_bang() + diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c index 9d945b1..767d737 100644 --- a/wiiremote/aka.wiiremote.c +++ b/wiiremote/aka.wiiremote.c @@ -13,6 +13,8 @@ #define SETSYM SETSYMBOL #define SETLONG SETFLOAT #define method t_method +//#define addbang(x) class_addbang(wiiremote_class, (x)) +//#define addmess(x) class_addmessage(class_wiiremote, (x)) static t_class *wiiremote_class; #else /* Max */ #include "ext.h" @@ -20,6 +22,7 @@ static t_class *wiiremote_class; #include "wiiremote.h" #include +#include #define kInterval 100 #define kMaxTrial 100 @@ -39,7 +42,7 @@ typedef struct _akawiiremote Boolean connected; void *statusOut; - void *dataOut + void *dataOut; } t_akawiiremote; void *akawiiremote_class; // the number of instance of this object @@ -53,6 +56,7 @@ void akawiiremote_irsensor(t_akawiiremote *x, long enable); void akawiiremote_vibration(t_akawiiremote *x, long enable); void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4); void akawiiremote_expansion(t_akawiiremote *x, long enable); +void akawiiremote_extraoutput(t_akawiiremote *x, long enable); void akawiiremote_getbattery(t_akawiiremote *x); void akawiiremote_getexpansion(t_akawiiremote *x); @@ -78,11 +82,11 @@ void main() NumVersion outSoftwareVersion; BluetoothHCIVersionInfo outHardwareVersion; - post("aka.wiiremote 1.0B6-UB by Masayuki Akamatsu"); + post("aka.wiiremote 1.0B7-UB by Masayuki Akamatsu"); - if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) + if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) // B7 { - if (outSoftwareVersion.majorRev < 1 || outSoftwareVersion.minorAndBugRev < 0x63) + if (outSoftwareVersion.majorRev < 1 && outSoftwareVersion.minorAndBugRev < 0x63) { error("requires Blutooth version 1.6.3 or later."); return; @@ -105,18 +109,22 @@ void main() A_GIMME,0); class_addbang(wiiremote_class,(t_method)akawiiremote_bang); + class_addmethod(wiiremote_class,(t_method)akawiiremote_address,gensym("address"),A_DEFSYMBOL, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("expansion"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("nunchuk"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_extraoutput,gensym("extraoutput"), A_DEFFLOAT, 0); // B7 class_addmethod(wiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); class_addmethod(wiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); - - class_addmethod(wiiremote_class,(t_method)akawiiremote_assist,gensym("assist"),A_CANT,0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getaddress,gensym("getaddress"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getcalibration,gensym("getcalibration"), 0); #else /* Max */ setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); @@ -130,6 +138,7 @@ void main() addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); addmess((method)akawiiremote_expansion,"expansion", A_DEFLONG, 0); addmess((method)akawiiremote_expansion,"nunchuk", A_DEFLONG, 0); + addmess((method)akawiiremote_extraoutput,"extraoutput", A_DEFLONG, 0); // B7 addmess((method)akawiiremote_getbattery,"getbattery",0); addmess((method)akawiiremote_getexpansion,"getexpansion",0); @@ -145,15 +154,10 @@ void main() void akawiiremote_bang(t_akawiiremote *x) { - t_atom av[5]; + t_atom av[7]; if (x->wiiremote->device == nil) return; // do nothing - -//#ifdef PD -// outlet_float(x->buttonsOut, (t_float) x->wiiremote->buttonData); -//#else /* Max */ -//#endif /* PD */ if (x->wiiremote->isExpansionPortAttached && x->wiiremote->isExpansionPortEnabled) { @@ -198,6 +202,18 @@ void akawiiremote_bang(t_akawiiremote *x) SETLONG(av + 2, x->wiiremote->nStickY); outlet_anything(x->dataOut, gensym(nunchukStr), 3, av); + if (x->wiiremote->isExtraOutputEnabled) + { + SETSYM(av, gensym("stick_calibration")); + SETLONG(av + 1, x->wiiremote->nunchukJoyStickCalibData.x_min); + SETLONG(av + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); + SETLONG(av + 3, x->wiiremote->nunchukJoyStickCalibData.x_center); + SETLONG(av + 4, x->wiiremote->nunchukJoyStickCalibData.y_min); + SETLONG(av + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); + SETLONG(av + 6, x->wiiremote->nunchukJoyStickCalibData.y_center); + outlet_anything(x->dataOut, gensym(nunchukStr), 7, av); + } + // Motion Sensor if (x->wiiremote->isMotionSensorEnabled) { @@ -207,6 +223,18 @@ void akawiiremote_bang(t_akawiiremote *x) SETLONG(av + 3, x->wiiremote->nAccZ); SETLONG(av + 4, x->wiiremote->nOrientation); outlet_anything(x->dataOut, gensym(nunchukStr), 5, av); + + if (x->wiiremote->isExtraOutputEnabled) + { + SETSYM(av, gensym("motion_calibration")); + SETLONG(av + 1, x->wiiremote->nunchukCalibData.accX_zero); + SETLONG(av + 2, x->wiiremote->nunchukCalibData.accY_zero); + SETLONG(av + 3, x->wiiremote->nunchukCalibData.accZ_zero); + SETLONG(av + 4, x->wiiremote->nunchukCalibData.accX_1g); + SETLONG(av + 5, x->wiiremote->nunchukCalibData.accY_1g); + SETLONG(av + 6, x->wiiremote->nunchukCalibData.accZ_1g); + outlet_anything(x->dataOut, gensym(nunchukStr), 7, av); + } } } } @@ -227,6 +255,31 @@ void akawiiremote_bang(t_akawiiremote *x) SETFLOAT(av + 3, x->wiiremote->angle); SETLONG (av + 4, x->wiiremote->tracking); outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + + if (x->wiiremote->isExtraOutputEnabled) // B7 + { + SETSYM(av, gensym("irraw")); + SETLONG(av + 1, 0); + SETLONG(av + 2, x->wiiremote->irData[0].x); + SETLONG(av + 3, x->wiiremote->irData[0].y); + SETLONG(av + 4, x->wiiremote->irData[0].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + SETLONG(av + 1, 1); + SETLONG(av + 2, x->wiiremote->irData[1].x); + SETLONG(av + 3, x->wiiremote->irData[1].y); + SETLONG(av + 4, x->wiiremote->irData[1].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + SETLONG(av + 1, 2); + SETLONG(av + 2, x->wiiremote->irData[2].x); + SETLONG(av + 3, x->wiiremote->irData[2].y); + SETLONG(av + 4, x->wiiremote->irData[2].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + SETLONG(av + 1, 3); + SETLONG(av + 2, x->wiiremote->irData[3].x); + SETLONG(av + 3, x->wiiremote->irData[3].y); + SETLONG(av + 4, x->wiiremote->irData[3].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + } } // Motion Sensor @@ -238,6 +291,18 @@ void akawiiremote_bang(t_akawiiremote *x) SETLONG(av + 3, x->wiiremote->accZ); SETLONG(av + 4, x->wiiremote->orientation); outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + + if (x->wiiremote->isExtraOutputEnabled) // B7 + { + SETSYM(av, gensym("motion_calibration")); + SETLONG(av + 1, x->wiiremote->wiiCalibData.accX_zero); + SETLONG(av + 2, x->wiiremote->wiiCalibData.accY_zero); + SETLONG(av + 3, x->wiiremote->wiiCalibData.accZ_zero); + SETLONG(av + 4, x->wiiremote->wiiCalibData.accX_1g); + SETLONG(av + 5, x->wiiremote->wiiCalibData.accY_1g); + SETLONG(av + 6, x->wiiremote->wiiCalibData.accZ_1g); + outlet_anything(x->dataOut, gensym(remoteStr), 7, av); + } } } @@ -255,6 +320,7 @@ void akawiiremote_address(t_akawiiremote *x, t_symbol *s) void akawiiremote_connect(t_akawiiremote *x) { + post("akawiiremote_connect"); t_atom status; Boolean result; @@ -278,6 +344,8 @@ void akawiiremote_foundFunc(t_akawiiremote *x) void akawiiremote_disconnect(t_akawiiremote *x) { + post("akawiiremote_disconnect"); + Boolean result; t_atom status; @@ -296,7 +364,6 @@ void akawiiremote_disconnect(t_akawiiremote *x) void akawiiremote_motionsensor(t_akawiiremote *x, long enable) { Boolean result; - t_atom status; result = wiiremote_motionsensor(x->wiiremote, enable); //SETLONG(&status, result); @@ -306,17 +373,20 @@ void akawiiremote_motionsensor(t_akawiiremote *x, long enable) void akawiiremote_irsensor(t_akawiiremote *x, long enable) { Boolean result; - t_atom status; result = wiiremote_irsensor(x->wiiremote, enable); //SETLONG(&status, result); //outlet_anything(x->statusOut, gensym("ir"), 1, &status); } +void akawiiremote_extraoutput(t_akawiiremote *x, long enable) // B7 +{ + x->wiiremote->isExtraOutputEnabled = enable; +} + void akawiiremote_expansion(t_akawiiremote *x, long enable) { Boolean result; - t_atom status; result = wiiremote_expansion(x->wiiremote, enable); //SETLONG(&status, result); @@ -326,7 +396,6 @@ void akawiiremote_expansion(t_akawiiremote *x, long enable) void akawiiremote_vibration(t_akawiiremote *x, long enable) { Boolean result; - t_atom status; result = wiiremote_vibration(x->wiiremote, enable); //SETLONG(&status, result); @@ -336,7 +405,6 @@ void akawiiremote_vibration(t_akawiiremote *x, long enable) void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) { Boolean result; - t_atom status; result = wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); //SETLONG(&status, result); @@ -509,12 +577,27 @@ void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) { - t_akawiiremote *x; - #ifdef PD - x = (t_akawiiremote *)pd_new(wiiremote_class); + t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + t_symbol *first_argument; + + x->statusOut = outlet_new(&x->x_obj, 0); + x->dataOut = outlet_new(&x->x_obj, &s_list); + +/* this sets the device name from the object arguments */ + first_argument = atom_getsymbolarg(0, ac, av); + if(first_argument != &s_) + atom_string(av, x->address, MAXPDSTRING-1); #else /* Max */ + t_akawiiremote *x; + x = (t_akawiiremote *)newobject(akawiiremote_class); + + x->statusOut = outlet_new(x, 0); + x->dataOut = outlet_new(x, 0); + + if (ac>0 && av[0].a_type == A_SYM) + strcpy(x->address, av[0].a_w.w_sym->s_name); #endif /* PD */ x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); @@ -529,22 +612,11 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) x->wiiremote->isLED2Illuminated = false; x->wiiremote->isLED3Illuminated = false; x->wiiremote->isLED4Illuminated = false; + x->wiiremote->isExtraOutputEnabled = false; } x->clock = clock_new(x, (method)akawiiremote_clock); -#ifdef PD - if (ac>0 && av[0].a_type == A_SYMBOL) - strcpy(x->address, av[0].a_w.w_symbol->s_name); - x->statusOut = outlet_new(&x->x_obj, 0); - x->dataOut = outlet_new(&x->x_obj, 0); -#else /* Max */ - if (ac>0 && av[0].a_type == A_SYM) - strcpy(x->address, av[0].a_w.w_sym->s_name); - - x->statusOut = outlet_new(x, 0); - x->dataOut = outlet_new(x, 0); -#endif /* PD */ x->connected = false; return x; diff --git a/wiiremote/wiiremote-help.pd b/wiiremote/wiiremote-help.pd index 737fe6b..5c8f610 100644 --- a/wiiremote/wiiremote-help.pd +++ b/wiiremote/wiiremote-help.pd @@ -1,21 +1,14 @@ -#N canvas 41 171 577 460 10; -#X obj 451 21 import io; -#X obj 213 388 wiiremote; -#X msg 168 207 connect; -#X msg 185 233 disconnect; -#X msg 286 237 motionsensor \$1; -#X obj 286 215 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +#N canvas 287 96 744 626 10; +#X msg 128 207 connect; +#X msg 141 228 disconnect; +#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1; -#X obj 406 215 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1; -#X msg 406 237 irsensor \$1; -#X obj 64 254 metro 100; -#X obj 64 233 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 -; -#X msg 376 290 getbatterylevel; -#X msg 376 310 getledstatus; -#X msg 376 330 getexpansionstatus; -#X msg 129 283 bang; +#X obj 127 285 metro 100; +#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 89 283 bang; #X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote with your computer (only required for the first use).; #X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs @@ -24,15 +17,64 @@ will start blinking.; blinking once its connected; #X text 49 139 - Start the [metro] to get updates from [wiiremote] ; -#X connect 2 0 1 0; -#X connect 3 0 1 0; -#X connect 4 0 1 0; +#X obj 399 526 pddp/print; +#X obj 354 556 pddp/print; +#X obj 354 410 route remote; +#X msg 503 290 getbattery; +#X msg 503 310 getled; +#X msg 503 330 getexpansion; +#X obj 489 431 print RIGHT; +#X obj 253 430 print LEFT; +#X obj 354 476 route motion buttons ir; +#X obj 444 497 pddp/print; +#X msg 294 224 ir \$1; +#X msg 218 225 motion \$1; +#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 344 224 vibration \$1; +#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 434 224 expansion \$1; +#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 524 223 extraoutput \$1; +#N canvas 254 342 450 300 address 0; +#X obj 176 252 outlet; +#X msg 206 126 getaddress; +#X msg 176 72 address 00-1e-35-4c-e6-f1; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X restore 25 462 pd address; +#X msg 503 352 getaddress; +#X obj 631 536 dac~; +#X obj 632 408 pddp/dsp; +#X obj 640 500 osc~ 100; +#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1; +#X connect 0 0 34 0; +#X connect 1 0 34 0; +#X connect 2 0 22 0; +#X connect 3 0 21 0; +#X connect 4 0 34 0; #X connect 5 0 4 0; -#X connect 6 0 7 0; -#X connect 7 0 1 0; -#X connect 8 0 1 0; -#X connect 9 0 8 0; -#X connect 10 0 1 0; -#X connect 11 0 1 0; -#X connect 12 0 1 0; -#X connect 13 0 1 0; +#X connect 6 0 34 0; +#X connect 13 0 19 0; +#X connect 13 1 17 0; +#X connect 14 0 34 0; +#X connect 15 0 34 0; +#X connect 16 0 34 0; +#X connect 19 0 12 0; +#X connect 19 1 11 0; +#X connect 19 2 20 0; +#X connect 21 0 34 0; +#X connect 22 0 34 0; +#X connect 23 0 24 0; +#X connect 24 0 34 0; +#X connect 25 0 26 0; +#X connect 26 0 34 0; +#X connect 27 0 28 0; +#X connect 28 0 34 0; +#X connect 30 0 34 0; +#X connect 33 0 31 0; +#X connect 33 0 31 1; +#X connect 34 0 18 0; +#X connect 34 1 13 0; diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c index 2caffb7..481085e 100644 --- a/wiiremote/wiiremote.c +++ b/wiiremote/wiiremote.c @@ -208,15 +208,16 @@ Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short l void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) { + post("checkDevice"); CFStringRef name; CFStringRef address; - + if (wiiremote_isconnected(wiiremote)) return; name = IOBluetoothDeviceGetName(device); address = IOBluetoothDeviceGetAddressString(device); - if (name != nil && address != nil) + if (name != nil && address != nil) { if (CFStringCompare(name, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) { @@ -233,17 +234,20 @@ void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) { + post("myFoundFunc"); checkDevice((WiiRemoteRef)refCon, device); } void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) { + post("myUpdatedFunc"); + checkDevice((WiiRemoteRef)refCon, device); } void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) { - IOReturn ret; + post("myCompleteFunc"); if (aborted) return; // called by stop ;) @@ -252,14 +256,10 @@ void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn wiiremote_stopsearch((WiiRemoteRef)refCon); return; } - - /* - ret = IOBluetoothDeviceInquiryStart(((WiiRemoteRef)refCon)->inquiry); - if (ret != kIOReturnSuccess) - { - wiiremote_stopsearch((WiiRemoteRef)refCon); - } - */ +#ifdef PD + // PD doesn't use the Carbon loop, so we have to manually control it + CFRunLoopStop( CFRunLoopGetCurrent() ); +#endif } //-------------------------------------------------------------------------------------------- @@ -274,11 +274,12 @@ Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) { + post("wiiremote_search"); IOReturn ret; if (wiiremote->inquiry != nil) return true; - + wiiremote->inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon((void *)wiiremote); IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); @@ -295,11 +296,15 @@ Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) wiiremote->inquiry = nil; return false; } +#ifdef PD + CFRunLoopRun(); // PD doesn't use the Carbon loop, so we have to manually control it +#endif return true; } Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) { + post("wiiremote_stopsearch"); IOReturn ret; if (wiiremote->inquiry == nil) @@ -841,7 +846,7 @@ Boolean wiiremote_connect(WiiRemoteRef wiiremote) Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) { - short i; + short i = 0; if (wiiremote->cchan) { diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h index f8ad39d..4a03f09 100644 --- a/wiiremote/wiiremote.h +++ b/wiiremote/wiiremote.h @@ -67,7 +67,6 @@ enum { WiiClassicControllerPlusButton }; - typedef UInt16 WiiExpansionPortType; enum{ WiiExpNotAttached, @@ -131,6 +130,7 @@ typedef struct _WiiRemoteRec Boolean isLED2Illuminated; Boolean isLED3Illuminated; Boolean isLED4Illuminated; + Boolean isExtraOutputEnabled; Boolean isExpansionPortAttached; -- cgit v1.2.1 From da3f6b1d47080e0162944834d18017c9a691c0b1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 10 Mar 2008 21:50:43 +0000 Subject: moved wiiremote to aka.wiiremote to reflect the name of the Max/MSP object. This is a direct port, so it makes sense to have the same name. svn path=/trunk/externals/io/; revision=9551 --- aka.wiiremote/COPYRIGHT.txt | 13 + aka.wiiremote/HISTORY.txt | 54 ++ aka.wiiremote/Makefile | 33 ++ aka.wiiremote/README.txt | 6 + aka.wiiremote/TODO | 7 + aka.wiiremote/aka.wiiremote.c | 642 +++++++++++++++++++++++ aka.wiiremote/wiiremote-help.pd | 80 +++ aka.wiiremote/wiiremote.c | 1087 +++++++++++++++++++++++++++++++++++++++ aka.wiiremote/wiiremote.h | 175 +++++++ wiiremote/COPYRIGHT.txt | 13 - wiiremote/HISTORY.txt | 54 -- wiiremote/Makefile | 33 -- wiiremote/README.txt | 6 - wiiremote/TODO | 7 - wiiremote/aka.wiiremote.c | 642 ----------------------- wiiremote/wiiremote-help.pd | 80 --- wiiremote/wiiremote.c | 1087 --------------------------------------- wiiremote/wiiremote.h | 175 ------- 18 files changed, 2097 insertions(+), 2097 deletions(-) create mode 100644 aka.wiiremote/COPYRIGHT.txt create mode 100644 aka.wiiremote/HISTORY.txt create mode 100644 aka.wiiremote/Makefile create mode 100644 aka.wiiremote/README.txt create mode 100644 aka.wiiremote/TODO create mode 100644 aka.wiiremote/aka.wiiremote.c create mode 100644 aka.wiiremote/wiiremote-help.pd create mode 100644 aka.wiiremote/wiiremote.c create mode 100644 aka.wiiremote/wiiremote.h delete mode 100644 wiiremote/COPYRIGHT.txt delete mode 100644 wiiremote/HISTORY.txt delete mode 100644 wiiremote/Makefile delete mode 100644 wiiremote/README.txt delete mode 100644 wiiremote/TODO delete mode 100644 wiiremote/aka.wiiremote.c delete mode 100644 wiiremote/wiiremote-help.pd delete mode 100644 wiiremote/wiiremote.c delete mode 100644 wiiremote/wiiremote.h diff --git a/aka.wiiremote/COPYRIGHT.txt b/aka.wiiremote/COPYRIGHT.txt new file mode 100644 index 0000000..b33233c --- /dev/null +++ b/aka.wiiremote/COPYRIGHT.txt @@ -0,0 +1,13 @@ +Max porting by Masayuki Akamatsu +Copyright (c) 2006, Masayuki Akamatsu +Based on "DarwiinRemote" by Hiroaki Kimura +Copyright (c) 2006, Hiroaki Kimura +All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/aka.wiiremote/HISTORY.txt b/aka.wiiremote/HISTORY.txt new file mode 100644 index 0000000..a0687b1 --- /dev/null +++ b/aka.wiiremote/HISTORY.txt @@ -0,0 +1,54 @@ +aka.wiiremote Version History + +1.0B6 : 2007.04.24 + +- The Classic Controller is supported. +- The help patch is updated. +- The URLs in [info] subpatch are updated. + +- 'expansion' message enables to use the expansion controller(Nunchuk or Classic Controller). +- 'nunchuk' message is obsolete. + You should use 'expansion' instead of it even though you can use it for the backward compatibility only. + +- The IR sensor and the expansion controller (ex. Nunchuk) can be used together. + +- The stability on PPC-Mac is a little improved. + You have to do the following steps every time you use the Wii Remote on PPC-Mac. + (You would set up only once on Intel-Mac.) +1: Delete "Nintendo RVL-CNT-01" on "Device" tab in "Bluetooth" System Preference. +2: Do the setup for Wii Remote. See http://max.iamas.ac.jp/2061/articles/121.html +3: Open "aka.wiiremote.help" and connect it. + + +1.0B5 : 2007.02.03 + +- Nunchuk is supported. +( Classic Controller is NOT supported.) +- device address is supported. +- outlets and output messages are changed. +- some input messages are simplified. +- help patch is expanded for Nunchuk. + + +1.0B4 : 2006.12.24 + +- multiple Wii remotes are supported. + + +1.0B3 : 2006.12.20 + +- data acquisition is improved. +- unusual vibration sound is resolved. + + +1.0B2 : 2006.12.15 + +- connection/disconnection is improved. +- IR sensor is supported. +- status report is supported +- help patch is rewritten. + + +1.0B1 : 2006.12.12 + +- first release \ No newline at end of file diff --git a/aka.wiiremote/Makefile b/aka.wiiremote/Makefile new file mode 100644 index 0000000..e222c9b --- /dev/null +++ b/aka.wiiremote/Makefile @@ -0,0 +1,33 @@ +TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') +EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') + +default: + make -C $(EXTERNALS_ROOT) $(TARGET) + +install: + make -C $(EXTERNALS_ROOT) $(TARGET)_install + +clean: + make -C $(EXTERNALS_ROOT) $(TARGET)_clean + +test_locations: + make -C $(EXTERNALS_ROOT) test_locations + +# for emacs +etags: + etags ../../../pd/src/*.h *.[ch] + make etags_`uname -s` + +etags_Darwin: + etags -a \ + /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \ + /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \ + /System/Library/Frameworks/Carbon.framework/Headers/*.h \ + /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[ch] + +etags_Linux: + etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: + etags -a /usr/include/*.h /usr/include/sys/*.h \ + /usr/local/include/*.h /usr/local/include/sys/*.h diff --git a/aka.wiiremote/README.txt b/aka.wiiremote/README.txt new file mode 100644 index 0000000..bdaf778 --- /dev/null +++ b/aka.wiiremote/README.txt @@ -0,0 +1,6 @@ + +This is a port of the Max class aka.wiiremote by Masayuki Akamatsu. Its +available here: + +http://www.iamas.ac.jp/~aka/max/#aka_wiiremote + diff --git a/aka.wiiremote/TODO b/aka.wiiremote/TODO new file mode 100644 index 0000000..a8da43d --- /dev/null +++ b/aka.wiiremote/TODO @@ -0,0 +1,7 @@ + + + - try out IOBluetoothLocalDeviceAvailable(wiiremote->inquiry); to see if that will set up the event loops (http://lists.apple.com/archives/bluetooth-dev/2006/Dec/msg00001.html) + + +- try CFRunLoopRun(); then CFRunLoopStop(CFRunLoopGetCurrent()); in akawiiremote_clock() and akawiiremote_bang() + diff --git a/aka.wiiremote/aka.wiiremote.c b/aka.wiiremote/aka.wiiremote.c new file mode 100644 index 0000000..767d737 --- /dev/null +++ b/aka.wiiremote/aka.wiiremote.c @@ -0,0 +1,642 @@ +// aka.wiiremote.c +// Copyright by Masayuki Akamatsu +// Code for PD by Hans-Christoph Steiner +// 1.0B1 : 2006.12.12 +// 1.0B2 : 2006.12.15 +// 1.0B3 : 2006.12.20 +// 1.0B4 : 2006.12.24 +// 1.0B5 : 2007.02.03 +// 1.0B6 : 2007.04.24 + +#ifdef PD +#include "m_pd.h" +#define SETSYM SETSYMBOL +#define SETLONG SETFLOAT +#define method t_method +//#define addbang(x) class_addbang(wiiremote_class, (x)) +//#define addmess(x) class_addmessage(class_wiiremote, (x)) +static t_class *wiiremote_class; +#else /* Max */ +#include "ext.h" +#endif /* PD */ + +#include "wiiremote.h" +#include +#include + +#define kInterval 100 +#define kMaxTrial 100 + +typedef struct _akawiiremote +{ +#ifdef PD + t_object x_obj; +#else /* Max */ + struct object obj; +#endif + + WiiRemoteRef wiiremote; + char address[32]; + + void *clock; + Boolean connected; + + void *statusOut; + void *dataOut; +} t_akawiiremote; + +void *akawiiremote_class; // the number of instance of this object + +void akawiiremote_bang(t_akawiiremote *x); +void akawiiremote_address(t_akawiiremote *x, t_symbol *s); +void akawiiremote_connect(t_akawiiremote *x); +void akawiiremote_disconnect(t_akawiiremote *x); +void akawiiremote_motionsensor(t_akawiiremote *x, long enable); +void akawiiremote_irsensor(t_akawiiremote *x, long enable); +void akawiiremote_vibration(t_akawiiremote *x, long enable); +void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4); +void akawiiremote_expansion(t_akawiiremote *x, long enable); +void akawiiremote_extraoutput(t_akawiiremote *x, long enable); + +void akawiiremote_getbattery(t_akawiiremote *x); +void akawiiremote_getexpansion(t_akawiiremote *x); +void akawiiremote_getled(t_akawiiremote *x); +void akawiiremote_getaddress(t_akawiiremote *x); +void akawiiremote_getcalibration(t_akawiiremote *x); + +void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s); +void akawiiremote_clock(t_akawiiremote *x); +void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); +void akawiiremote_free(t_akawiiremote *x); + +char remoteStr[] = "remote"; +char nunchukStr[] = "nunchuk"; +char classicStr[] = "classic"; + +#ifdef PD +void wiiremote_setup() +#else /* Max */ +void main() +#endif /* PD */ +{ + NumVersion outSoftwareVersion; + BluetoothHCIVersionInfo outHardwareVersion; + + post("aka.wiiremote 1.0B7-UB by Masayuki Akamatsu"); + + if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) // B7 + { + if (outSoftwareVersion.majorRev < 1 && outSoftwareVersion.minorAndBugRev < 0x63) + { + error("requires Blutooth version 1.6.3 or later."); + return; + } + } + else + { + error("can't get Bluetooth version."); + return; + } + +#ifdef PD + post("\tPd port by Hans-Christoph Steiner"); + + wiiremote_class = class_new(gensym("wiiremote"), + (t_newmethod)akawiiremote_new, + (t_method)akawiiremote_free, + sizeof(t_akawiiremote), + CLASS_DEFAULT, + A_GIMME,0); + + class_addbang(wiiremote_class,(t_method)akawiiremote_bang); + class_addmethod(wiiremote_class,(t_method)akawiiremote_address,gensym("address"),A_DEFSYMBOL, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("expansion"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("nunchuk"), A_DEFFLOAT, 0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_extraoutput,gensym("extraoutput"), A_DEFFLOAT, 0); // B7 + + class_addmethod(wiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getaddress,gensym("getaddress"),0); + class_addmethod(wiiremote_class,(t_method)akawiiremote_getcalibration,gensym("getcalibration"), 0); +#else /* Max */ + setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); + + addbang((method)akawiiremote_bang); + addmess((method)akawiiremote_address,"address",A_DEFSYM, 0); + addmess((method)akawiiremote_connect,"connect", 0); + addmess((method)akawiiremote_disconnect,"disconnect",0); + addmess((method)akawiiremote_motionsensor,"motion", A_DEFLONG, 0); + addmess((method)akawiiremote_irsensor,"ir", A_DEFLONG, 0); + addmess((method)akawiiremote_vibration,"vibration", A_DEFLONG, 0); + addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); + addmess((method)akawiiremote_expansion,"expansion", A_DEFLONG, 0); + addmess((method)akawiiremote_expansion,"nunchuk", A_DEFLONG, 0); + addmess((method)akawiiremote_extraoutput,"extraoutput", A_DEFLONG, 0); // B7 + + addmess((method)akawiiremote_getbattery,"getbattery",0); + addmess((method)akawiiremote_getexpansion,"getexpansion",0); + addmess((method)akawiiremote_getled,"getled",0); + addmess((method)akawiiremote_getaddress,"getaddress",0); + addmess((method)akawiiremote_getcalibration,"getcalibration", 0); + + addmess((method)akawiiremote_assist,"assist",A_CANT,0); +#endif /* PD */ +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_bang(t_akawiiremote *x) +{ + t_atom av[7]; + + if (x->wiiremote->device == nil) + return; // do nothing + + if (x->wiiremote->isExpansionPortAttached && x->wiiremote->isExpansionPortEnabled) + { + // Classic Controller + if (x->wiiremote->expType == WiiClassicController) + { + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->cButtonData); + outlet_anything(x->dataOut, gensym(classicStr), 2, av); + + // Joystick 1 + SETSYM(av, gensym("stick1")); + SETLONG(av + 1, x->wiiremote->cStickX1); + SETLONG(av + 2, x->wiiremote->cStickY1); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + + // Joystick 2 + SETSYM(av, gensym("stick2")); + SETLONG(av + 1, x->wiiremote->cStickX2); + SETLONG(av + 2, x->wiiremote->cStickY2); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + + // Analog + SETSYM(av, gensym("analog")); + SETLONG(av + 1, x->wiiremote->cAnalogL); + SETLONG(av + 2, x->wiiremote->cAnalogR); + outlet_anything(x->dataOut, gensym(classicStr), 3, av); + } + + // Nunchuk + if (x->wiiremote->expType == WiiNunchuk) + { + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->nButtonData); + outlet_anything(x->dataOut, gensym(nunchukStr), 2, av); + + // Joystick + SETSYM(av, gensym("stick")); + SETLONG(av + 1, x->wiiremote->nStickX); + SETLONG(av + 2, x->wiiremote->nStickY); + outlet_anything(x->dataOut, gensym(nunchukStr), 3, av); + + if (x->wiiremote->isExtraOutputEnabled) + { + SETSYM(av, gensym("stick_calibration")); + SETLONG(av + 1, x->wiiremote->nunchukJoyStickCalibData.x_min); + SETLONG(av + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); + SETLONG(av + 3, x->wiiremote->nunchukJoyStickCalibData.x_center); + SETLONG(av + 4, x->wiiremote->nunchukJoyStickCalibData.y_min); + SETLONG(av + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); + SETLONG(av + 6, x->wiiremote->nunchukJoyStickCalibData.y_center); + outlet_anything(x->dataOut, gensym(nunchukStr), 7, av); + } + + // Motion Sensor + if (x->wiiremote->isMotionSensorEnabled) + { + SETSYM(av, gensym("motion")); + SETLONG(av + 1, x->wiiremote->nAccX); + SETLONG(av + 2, x->wiiremote->nAccY); + SETLONG(av + 3, x->wiiremote->nAccZ); + SETLONG(av + 4, x->wiiremote->nOrientation); + outlet_anything(x->dataOut, gensym(nunchukStr), 5, av); + + if (x->wiiremote->isExtraOutputEnabled) + { + SETSYM(av, gensym("motion_calibration")); + SETLONG(av + 1, x->wiiremote->nunchukCalibData.accX_zero); + SETLONG(av + 2, x->wiiremote->nunchukCalibData.accY_zero); + SETLONG(av + 3, x->wiiremote->nunchukCalibData.accZ_zero); + SETLONG(av + 4, x->wiiremote->nunchukCalibData.accX_1g); + SETLONG(av + 5, x->wiiremote->nunchukCalibData.accY_1g); + SETLONG(av + 6, x->wiiremote->nunchukCalibData.accZ_1g); + outlet_anything(x->dataOut, gensym(nunchukStr), 7, av); + } + } + } + } + + // Wii Remote + + // Buttons + SETSYM(av, gensym("buttons")); + SETLONG(av + 1, x->wiiremote->buttonData); + outlet_anything(x->dataOut, gensym(remoteStr), 2, av); + + // IR Sensor + if (x->wiiremote->isIRSensorEnabled) + { + SETSYM(av, gensym("ir")); + SETFLOAT(av + 1, x->wiiremote->posX); // posX and posY are "float"???? + SETFLOAT(av + 2, x->wiiremote->posY); + SETFLOAT(av + 3, x->wiiremote->angle); + SETLONG (av + 4, x->wiiremote->tracking); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + + if (x->wiiremote->isExtraOutputEnabled) // B7 + { + SETSYM(av, gensym("irraw")); + SETLONG(av + 1, 0); + SETLONG(av + 2, x->wiiremote->irData[0].x); + SETLONG(av + 3, x->wiiremote->irData[0].y); + SETLONG(av + 4, x->wiiremote->irData[0].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + SETLONG(av + 1, 1); + SETLONG(av + 2, x->wiiremote->irData[1].x); + SETLONG(av + 3, x->wiiremote->irData[1].y); + SETLONG(av + 4, x->wiiremote->irData[1].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + SETLONG(av + 1, 2); + SETLONG(av + 2, x->wiiremote->irData[2].x); + SETLONG(av + 3, x->wiiremote->irData[2].y); + SETLONG(av + 4, x->wiiremote->irData[2].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + SETLONG(av + 1, 3); + SETLONG(av + 2, x->wiiremote->irData[3].x); + SETLONG(av + 3, x->wiiremote->irData[3].y); + SETLONG(av + 4, x->wiiremote->irData[3].s); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + } + } + + // Motion Sensor + if (x->wiiremote->isMotionSensorEnabled) + { + SETSYM(av, gensym("motion")); + SETLONG(av + 1, x->wiiremote->accX); + SETLONG(av + 2, x->wiiremote->accY); + SETLONG(av + 3, x->wiiremote->accZ); + SETLONG(av + 4, x->wiiremote->orientation); + outlet_anything(x->dataOut, gensym(remoteStr), 5, av); + + if (x->wiiremote->isExtraOutputEnabled) // B7 + { + SETSYM(av, gensym("motion_calibration")); + SETLONG(av + 1, x->wiiremote->wiiCalibData.accX_zero); + SETLONG(av + 2, x->wiiremote->wiiCalibData.accY_zero); + SETLONG(av + 3, x->wiiremote->wiiCalibData.accZ_zero); + SETLONG(av + 4, x->wiiremote->wiiCalibData.accX_1g); + SETLONG(av + 5, x->wiiremote->wiiCalibData.accY_1g); + SETLONG(av + 6, x->wiiremote->wiiCalibData.accZ_1g); + outlet_anything(x->dataOut, gensym(remoteStr), 7, av); + } + } +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_address(t_akawiiremote *x, t_symbol *s) +{ + if (*(s->s_name) == 0) // if null string + *(x->address) = 0; + else + strcpy(x->address, s->s_name); +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_connect(t_akawiiremote *x) +{ + post("akawiiremote_connect"); + t_atom status; + Boolean result; + + if (wiiremote_isconnected(x->wiiremote)) + { + SETLONG(&status, -1); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } + else + { + result = wiiremote_search(x->wiiremote, x->address); // start searching the device + x->connected = false; + clock_unset(x->clock); // stop clock + clock_delay(x->clock, 0); // start clock to check the device found + } +} + +void akawiiremote_foundFunc(t_akawiiremote *x) +{ +} + +void akawiiremote_disconnect(t_akawiiremote *x) +{ + post("akawiiremote_disconnect"); + + Boolean result; + t_atom status; + + clock_unset(x->clock); // stop clock + wiiremote_stopsearch(x->wiiremote); + + result = wiiremote_disconnect(x->wiiremote); + SETLONG(&status, result); + outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); + + x->connected = !result; +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_motionsensor(t_akawiiremote *x, long enable) +{ + Boolean result; + + result = wiiremote_motionsensor(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("motion"), 1, &status); +} + +void akawiiremote_irsensor(t_akawiiremote *x, long enable) +{ + Boolean result; + + result = wiiremote_irsensor(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("ir"), 1, &status); +} + +void akawiiremote_extraoutput(t_akawiiremote *x, long enable) // B7 +{ + x->wiiremote->isExtraOutputEnabled = enable; +} + +void akawiiremote_expansion(t_akawiiremote *x, long enable) +{ + Boolean result; + + result = wiiremote_expansion(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("nunchuk"), 1, &status); +} + +void akawiiremote_vibration(t_akawiiremote *x, long enable) +{ + Boolean result; + + result = wiiremote_vibration(x->wiiremote, enable); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("vibration"), 1, &status); +} + +void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) +{ + Boolean result; + + result = wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); + //SETLONG(&status, result); + //outlet_anything(x->statusOut, gensym("led"), 1, &status); +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_getbattery(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("battery"), 0, nil); + } + else + { + t_atom status; + + SETFLOAT(&status, x->wiiremote->batteryLevel); + outlet_anything(x->statusOut, gensym("battery"), 1, &status); + } +} + +void akawiiremote_getexpansion(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("expansion"), 0, nil); + } + else + { + t_atom status; + if (x->wiiremote->isExpansionPortAttached) + SETLONG(&status, x->wiiremote->expType); + else + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("expansion"), 1, &status); + } +} + +void akawiiremote_getled(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("led"), 0, nil); + } + else + { + t_atom list[4]; + + SETLONG(list, x->wiiremote->isLED1Illuminated); + SETLONG(list + 1, x->wiiremote->isLED2Illuminated); + SETLONG(list + 2, x->wiiremote->isLED3Illuminated); + SETLONG(list + 3, x->wiiremote->isLED4Illuminated); + outlet_anything(x->statusOut, gensym("led"), 4, list); + } +} + +void akawiiremote_getcalibration(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("calibration"), 0, nil); + } + else + { + t_atom list[8]; + + if (x->wiiremote->isExpansionPortAttached) + { + SETSYM(list, gensym(nunchukStr)); + SETSYM(list + 1, gensym("stick")); + SETLONG(list + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); + SETLONG(list + 3, x->wiiremote->nunchukJoyStickCalibData.x_min); + SETLONG(list + 4, x->wiiremote->nunchukJoyStickCalibData.x_center); + SETLONG(list + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); + SETLONG(list + 6, x->wiiremote->nunchukJoyStickCalibData.y_min); + SETLONG(list + 7, x->wiiremote->nunchukJoyStickCalibData.y_center); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + + SETSYM(list + 1, gensym("motion")); + SETLONG(list + 2, x->wiiremote->nunchukCalibData.accX_zero); + SETLONG(list + 3, x->wiiremote->nunchukCalibData.accY_zero); + SETLONG(list + 4, x->wiiremote->nunchukCalibData.accZ_zero); + SETLONG(list + 5, x->wiiremote->nunchukCalibData.accX_1g); + SETLONG(list + 6, x->wiiremote->nunchukCalibData.accY_1g); + SETLONG(list + 7, x->wiiremote->nunchukCalibData.accZ_1g); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + } + + SETSYM(list, gensym(remoteStr)); + SETSYM(list + 1, gensym("motion")); + SETLONG(list + 2, x->wiiremote->wiiCalibData.accX_zero); + SETLONG(list + 3, x->wiiremote->wiiCalibData.accY_zero); + SETLONG(list + 4, x->wiiremote->wiiCalibData.accZ_zero); + SETLONG(list + 5, x->wiiremote->wiiCalibData.accX_1g); + SETLONG(list + 6, x->wiiremote->wiiCalibData.accY_1g); + SETLONG(list + 7, x->wiiremote->wiiCalibData.accZ_1g); + outlet_anything(x->statusOut, gensym("calibration"), 8, list); + } +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_getaddress(t_akawiiremote *x) +{ + if (x->wiiremote->device == nil) + { + outlet_anything(x->statusOut, gensym("address"), 0, nil); + } + else + { + char str[32]; + t_atom address; + + wiiremote_getaddress(x->wiiremote, str); + SETSYM(&address, gensym(str)); + outlet_anything(x->statusOut, gensym("address"), 1, &address); + } +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_clock(t_akawiiremote *x) +{ + Boolean connection; + t_atom status; + + connection = wiiremote_isconnected(x->wiiremote); + + if (x->connected == false && connection == true) // if the device is connected... + { + wiiremote_getstatus(x->wiiremote); + x->connected = true; + SETLONG(&status, 1); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } + + if (x->connected == true && connection == false) + { + x->connected = false; + SETLONG(&status, 0); + outlet_anything(x->statusOut, gensym("connect"), 1, &status); + } + + clock_delay(x->clock, kInterval); // restart clock +} + +//-------------------------------------------------------------------------------------------- + +void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) +{ +#ifndef PD /* Max */ + if (m==ASSIST_INLET) + { + sprintf(s,"connect, bang, disconnect...."); + } + else +#endif /* NOT PD */ + { + switch(a) + { + case 0: sprintf(s,"data messages"); break; + case 2: sprintf(s,"status messages"); break; + } + } +} + +//-------------------------------------------------------------------------------------------- + +void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) +{ +#ifdef PD + t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + t_symbol *first_argument; + + x->statusOut = outlet_new(&x->x_obj, 0); + x->dataOut = outlet_new(&x->x_obj, &s_list); + +/* this sets the device name from the object arguments */ + first_argument = atom_getsymbolarg(0, ac, av); + if(first_argument != &s_) + atom_string(av, x->address, MAXPDSTRING-1); +#else /* Max */ + t_akawiiremote *x; + + x = (t_akawiiremote *)newobject(akawiiremote_class); + + x->statusOut = outlet_new(x, 0); + x->dataOut = outlet_new(x, 0); + + if (ac>0 && av[0].a_type == A_SYM) + strcpy(x->address, av[0].a_w.w_sym->s_name); +#endif /* PD */ + + x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); + if (x->wiiremote != nil) + { + wiiremote_init(x->wiiremote); + x->wiiremote->isMotionSensorEnabled = true; + x->wiiremote->isIRSensorEnabled = false; + x->wiiremote->isVibrationEnabled = false; + x->wiiremote->isExpansionPortEnabled = false; + x->wiiremote->isLED1Illuminated = false; + x->wiiremote->isLED2Illuminated = false; + x->wiiremote->isLED3Illuminated = false; + x->wiiremote->isLED4Illuminated = false; + x->wiiremote->isExtraOutputEnabled = false; + } + + x->clock = clock_new(x, (method)akawiiremote_clock); + + x->connected = false; + + return x; +} + +void akawiiremote_free(t_akawiiremote *x) +{ + if (x->wiiremote != nil) + { + if (wiiremote_isconnected(x->wiiremote)) + wiiremote_disconnect(x->wiiremote); + freebytes(x->wiiremote, sizeof(WiiRemoteRec)); + x->wiiremote = nil; + } + + clock_unset(x->clock); +#ifdef PD + clock_free(x->clock); +#else /* Max */ + freeobject((t_object *)x->clock); +#endif /* PD */ +} + diff --git a/aka.wiiremote/wiiremote-help.pd b/aka.wiiremote/wiiremote-help.pd new file mode 100644 index 0000000..5c8f610 --- /dev/null +++ b/aka.wiiremote/wiiremote-help.pd @@ -0,0 +1,80 @@ +#N canvas 287 96 744 626 10; +#X msg 128 207 connect; +#X msg 141 228 disconnect; +#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 127 285 metro 100; +#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 89 283 bang; +#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote +with your computer (only required for the first use).; +#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs +will start blinking.; +#X text 49 109 - Click on the [connect( message \, the LEDs will stop +blinking once its connected; +#X text 49 139 - Start the [metro] to get updates from [wiiremote] +; +#X obj 399 526 pddp/print; +#X obj 354 556 pddp/print; +#X obj 354 410 route remote; +#X msg 503 290 getbattery; +#X msg 503 310 getled; +#X msg 503 330 getexpansion; +#X obj 489 431 print RIGHT; +#X obj 253 430 print LEFT; +#X obj 354 476 route motion buttons ir; +#X obj 444 497 pddp/print; +#X msg 294 224 ir \$1; +#X msg 218 225 motion \$1; +#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 344 224 vibration \$1; +#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 434 224 expansion \$1; +#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 524 223 extraoutput \$1; +#N canvas 254 342 450 300 address 0; +#X obj 176 252 outlet; +#X msg 206 126 getaddress; +#X msg 176 72 address 00-1e-35-4c-e6-f1; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X restore 25 462 pd address; +#X msg 503 352 getaddress; +#X obj 631 536 dac~; +#X obj 632 408 pddp/dsp; +#X obj 640 500 osc~ 100; +#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1; +#X connect 0 0 34 0; +#X connect 1 0 34 0; +#X connect 2 0 22 0; +#X connect 3 0 21 0; +#X connect 4 0 34 0; +#X connect 5 0 4 0; +#X connect 6 0 34 0; +#X connect 13 0 19 0; +#X connect 13 1 17 0; +#X connect 14 0 34 0; +#X connect 15 0 34 0; +#X connect 16 0 34 0; +#X connect 19 0 12 0; +#X connect 19 1 11 0; +#X connect 19 2 20 0; +#X connect 21 0 34 0; +#X connect 22 0 34 0; +#X connect 23 0 24 0; +#X connect 24 0 34 0; +#X connect 25 0 26 0; +#X connect 26 0 34 0; +#X connect 27 0 28 0; +#X connect 28 0 34 0; +#X connect 30 0 34 0; +#X connect 33 0 31 0; +#X connect 33 0 31 1; +#X connect 34 0 18 0; +#X connect 34 1 13 0; diff --git a/aka.wiiremote/wiiremote.c b/aka.wiiremote/wiiremote.c new file mode 100644 index 0000000..481085e --- /dev/null +++ b/aka.wiiremote/wiiremote.c @@ -0,0 +1,1087 @@ +// wiiremote.c +// Copyright by Masayuki Akamatsu +// Based on "DarwiinRemote" by Hiroaki Kimura + +#include "wiiremote.h" +#include + +// this type is used a lot (data array): +typedef unsigned char darr[]; + +#define kTrial 10 +#define kWait 10000 +// the unit of kWait is microseconds, thus 10000 means 10ms + +#define kWiiIRPixelsWidth 1024.0 +#define kWiiIRPixelsHeight 768.0 + + +Boolean requestUpdates(WiiRemoteRef wiiremote); +void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event); + + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +void wiiremote_init(WiiRemoteRef wiiremote) +{ + wiiremote->inquiry = nil; + wiiremote->device = nil; + wiiremote->ichan = nil; + wiiremote->cchan = nil; + + wiiremote->address = nil; + + wiiremote->accX = 0x10; + wiiremote->accY = 0x10; + wiiremote->accZ = 0x10; + wiiremote->buttonData = 0; + + wiiremote->lowZ = 0; + wiiremote->lowX = 0; + wiiremote->leftPoint = -1; + wiiremote->tracking = false; + + wiiremote->batteryLevel = 0; + + wiiremote->readingRegister = false; + wiiremote->isMotionSensorEnabled = false; + wiiremote->isVibrationEnabled = false; + wiiremote->isIRSensorEnabled = false; + wiiremote->wiiIRMode = kWiiIRModeExtended; + wiiremote->isExpansionPortEnabled = false; + wiiremote->isExpansionPortAttached = false; + wiiremote->expType = WiiExpNotAttached; + + wiiremote->isLED1Illuminated = false; + wiiremote->isLED2Illuminated = false; + wiiremote->isLED3Illuminated = false; + wiiremote->isLED4Illuminated = false; + + wiiremote->nAccX = 0x10; + wiiremote->nAccY = 0x10; + wiiremote->nAccZ = 0x10; + wiiremote->nButtonData = 0; + + wiiremote->nLowZ = 0; + wiiremote->nLowX = 0; + +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +Boolean openCChan(WiiRemoteRef wiiremote) +{ + short i; + IOReturn ret; + + // open L2CAPChannel : BluetoothL2CAPPSM = 17 + for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) + { + wiiremote->cchan = nil; + IOBluetoothDeviceCloseConnection(wiiremote->device); + return false; + } + IOBluetoothObjectRetain(wiiremote->cchan); + + return (ret==kIOReturnSuccess); +} + +Boolean openIChan(WiiRemoteRef wiiremote) +{ + short i; + IOReturn ret; + + // open L2CAPChannel : BluetoothL2CAPPSM = 19 + for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) + { + wiiremote->ichan = nil; + IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); + IOBluetoothObjectRelease(wiiremote->cchan); + IOBluetoothDeviceCloseConnection(wiiremote->device); + return false; + } + IOBluetoothObjectRetain(wiiremote->ichan); + + return (ret==kIOReturnSuccess); +} + +//-------------------------------------------------------------------------------------------- + +Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, unsigned short length) +{ + unsigned char buf[40]; + IOReturn ret; + int i; + + memset(buf,0,40); + buf[0] = 0x52; + memcpy(buf+1, data, length); + if (buf[1] == 0x16) + length=23; + else + length++; + + usleep(kWait); // wait 10ms // Done to make sure commands don't happen too fast. + + for (i = 0; icchan, buf, length); + if (ret == kIOReturnSuccess) + break; + usleep(kWait); + } + + if (ret != kIOReturnSuccess) + wiiremote_disconnect(wiiremote); + + return (ret==kIOReturnSuccess); +} + +Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, unsigned short length) +{ + unsigned char cmd[22]; + int i; + unsigned long addr = address; + + + for(i=0 ; i>24) & 0xFF; + cmd[2] = (addr>>16) & 0xFF; + cmd[3] = (addr>> 8) & 0xFF; + cmd[4] = (addr>> 0) & 0xFF; + cmd[5] = length; + + // and of course the vibration flag, as usual + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + + data = cmd; + + return sendCommand(wiiremote, cmd, 22); +} + +Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short length) +{ + + unsigned char cmd[7]; + unsigned long addr = address; + unsigned short len = length; + + cmd[0] = 0x17; + cmd[1] = (addr>>24)&0xFF; + cmd[2] = (addr>>16)&0xFF; + cmd[3] = (addr>> 8)&0xFF; + cmd[4] = (addr>> 0)&0xFF; + + cmd[5] = (len >> 8)&0xFF; + cmd[6] = (len >> 0)&0xFF; + + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (cmd[1] & 0x02) wiiremote->readingRegister = true; + + return sendCommand(wiiremote, cmd, 7); +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) +{ + post("checkDevice"); + CFStringRef name; + CFStringRef address; + + if (wiiremote_isconnected(wiiremote)) + return; + + name = IOBluetoothDeviceGetName(device); + address = IOBluetoothDeviceGetAddressString(device); + if (name != nil && address != nil) + { + if (CFStringCompare(name, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) + { + if ( CFStringGetLength(wiiremote->address) == 0 + || CFStringCompare(address, wiiremote->address, kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + wiiremote->device = IOBluetoothObjectRetain(device); + if ( wiiremote_connect(wiiremote) == false ) + wiiremote_disconnect(wiiremote); + } + } + } +} + +void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) +{ + post("myFoundFunc"); + checkDevice((WiiRemoteRef)refCon, device); +} + +void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) +{ + post("myUpdatedFunc"); + + checkDevice((WiiRemoteRef)refCon, device); +} + +void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) +{ + post("myCompleteFunc"); + + if (aborted) return; // called by stop ;) + + if (error != kIOReturnSuccess) + { + wiiremote_stopsearch((WiiRemoteRef)refCon); + return; + } +#ifdef PD + // PD doesn't use the Carbon loop, so we have to manually control it + CFRunLoopStop( CFRunLoopGetCurrent() ); +#endif +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) +{ + Boolean result; + + result = wiiremote->device != nil && IOBluetoothDeviceIsConnected(wiiremote->device); + return result; +} + +Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) +{ + post("wiiremote_search"); + IOReturn ret; + + if (wiiremote->inquiry != nil) + return true; + + wiiremote->inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon((void *)wiiremote); + IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); + IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); + IOBluetoothDeviceInquirySetCompleteCallback(wiiremote->inquiry, myCompleteFunc); + + if (wiiremote->address != nil) + CFRelease(wiiremote->address); + wiiremote->address = CFStringCreateWithCString(nil, address, kCFStringEncodingMacRoman); + + ret = IOBluetoothDeviceInquiryStart(wiiremote->inquiry); + if (ret != kIOReturnSuccess) + { + IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); + wiiremote->inquiry = nil; + return false; + } +#ifdef PD + CFRunLoopRun(); // PD doesn't use the Carbon loop, so we have to manually control it +#endif + return true; +} + +Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) +{ + post("wiiremote_stopsearch"); + IOReturn ret; + + if (wiiremote->inquiry == nil) + { + return true; // already stopped + } + + ret = IOBluetoothDeviceInquiryStop(wiiremote->inquiry); + + if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted) + { + // kIOReturnNotPermitted is if it's already stopped + } + + IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); + wiiremote->inquiry = nil; + + return (ret==kIOReturnSuccess); +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +unsigned char decrypt(unsigned char data) +{ + return (data ^ 0x17) + 0x17; +} + +//-------------------------------------------------------------------------------------------- + +/** +* Handle report 0x21 (Read Data) from wiimote. + * dp[0] = Bluetooth header + * dp[1] = (0x21) Report/Channel ID + * dp[2] = Wiimote Buttons + * dp[3] = Wiimote Buttons + * dp[4] = High 4 bits = payload size; Low 4 bits = Error flag (0 = all good) + * dp[5] = Offset of memory read + * dp[6] = Offset of memory read + * dp[7+] = the Data. + **/ + +void handleRAMData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + // specify attached expasion device + if ((dp[5] == 0x00) && (dp[6] == 0xF0)) + { + if (decrypt(dp[21]) == 0x00) + { + wiiremote->expType = WiiNunchuk; + } + else + if (decrypt(dp[21]) == 0x01) + { + wiiremote->expType = WiiClassicController; + } + else + { + wiiremote->expType = WiiExpNotAttached; + } + // initExpPort = NO; + return; + } + + // wiimote calibration data + if (!wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) + { + wiiremote->wiiCalibData.accX_zero = dp[7]; + wiiremote->wiiCalibData.accY_zero = dp[8]; + wiiremote->wiiCalibData.accZ_zero = dp[9]; + + //dp[10] - unknown/unused + + wiiremote->wiiCalibData.accX_1g = dp[11]; + wiiremote->wiiCalibData.accY_1g = dp[12]; + wiiremote->wiiCalibData.accZ_1g = dp[13]; + return; + } + + // expansion device calibration data. + if (wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) + { + if (wiiremote->expType == WiiNunchuk) + { + //nunchuk calibration data + wiiremote->nunchukCalibData.accX_zero = decrypt(dp[7]); + wiiremote->nunchukCalibData.accY_zero = decrypt(dp[8]); + wiiremote->nunchukCalibData.accZ_zero = decrypt(dp[9]); + + wiiremote->nunchukCalibData.accX_1g = decrypt(dp[11]); + wiiremote->nunchukCalibData.accY_1g = decrypt(dp[12]); + wiiremote->nunchukCalibData.accZ_1g = decrypt(dp[13]); + + wiiremote->nunchukJoyStickCalibData.x_max = decrypt(dp[15]); + wiiremote->nunchukJoyStickCalibData.x_min = decrypt(dp[16]); + wiiremote->nunchukJoyStickCalibData.x_center = decrypt(dp[17]); + + wiiremote->nunchukJoyStickCalibData.y_max = decrypt(dp[18]); + wiiremote->nunchukJoyStickCalibData.y_min = decrypt(dp[19]); + wiiremote->nunchukJoyStickCalibData.y_center = decrypt(dp[20]); + + return; + } + else + if (wiiremote->expType == WiiClassicController) + { + //classic controller calibration data (probably) + } + } + + // wii remote buttons + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; +} + +void handleStatusReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + wiiremote->batteryLevel = (double)dp[7]; + wiiremote->batteryLevel /= (double)0xC0; // C0 = fully charged. + + if ((dp[4] & 0x02)) //some device attached to Wiimote + { + wiiremote->isExpansionPortAttached = true; + // initExpPort = YES; + + Boolean ret = writeData(wiiremote, (darr){0x00}, 0x04A40040, 1); // Initialize the device + + if (ret == false) + { + wiiremote->isExpansionPortAttached = false; + return; + } + + usleep(kWait); // Give the write a chance to be processed. + + ret = readData(wiiremote, 0x04A400F0, 16); // read expansion device type + if (ret == false) + { + wiiremote->isExpansionPortAttached = false; + } + } + else + { // unplugged + wiiremote->isExpansionPortAttached = false; + wiiremote->expType = WiiExpNotAttached; + } + + if (dp[4] & 0x10) + wiiremote->isLED1Illuminated = true; + else + wiiremote->isLED1Illuminated = false; + + if (dp[4] & 0x20) + wiiremote->isLED2Illuminated = true; + else + wiiremote->isLED2Illuminated = false; + + if (dp[4] & 0x40) + wiiremote->isLED3Illuminated = true; + else + wiiremote->isLED3Illuminated = false; + + if (dp[4] & 0x80) + wiiremote->isLED4Illuminated = true; + else + wiiremote->isLED4Illuminated = false; +} + +void handleExtensionData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + unsigned char startByte; + + switch (dp[1]) { + case 0x34 : + startByte = 4; + break; + case 0x35 : + startByte = 7; + break; + case 0x36 : + startByte = 14; + break; + case 0x37 : + startByte = 17; + break; + default: + return; // This shouldn't ever happen. + break; + } + + if (wiiremote->expType == WiiNunchuk) + { + wiiremote->nStickX = decrypt(dp[startByte]); + wiiremote->nStickY = decrypt(dp[startByte +1]); + wiiremote->nAccX = decrypt(dp[startByte +2]); + wiiremote->nAccY = decrypt(dp[startByte +3]); + wiiremote->nAccZ = decrypt(dp[startByte +4]); + wiiremote->nButtonData = decrypt(dp[startByte +5]); + + wiiremote->nLowZ = wiiremote->nLowZ * .9 + wiiremote->nAccZ * .1; + wiiremote->nLowX = wiiremote->nLowX * .9 + wiiremote->nAccX * .1; + + float absx = abs(wiiremote->nLowX - 128); + float absz = abs(wiiremote->nLowZ - 128); + + if (wiiremote->nOrientation == 0 || wiiremote->nOrientation == 2) absx -= 5; + if (wiiremote->nOrientation == 1 || wiiremote->nOrientation == 3) absz -= 5; + + if (absz >= absx) + { + if (absz > 5) + wiiremote->nOrientation = (wiiremote->nLowZ > 128) ? 0 : 2; + } + else + { + if (absx > 5) + wiiremote->nOrientation = (wiiremote->nLowX > 128) ? 3 : 1; + } + } + else + if (wiiremote->expType == WiiClassicController) + { + wiiremote->cButtonData = (unsigned short)(decrypt(dp[startByte + 4]) << 8) + decrypt(dp[startByte + 5]); + wiiremote->cButtonData = ~wiiremote->cButtonData; // bit reverse + + wiiremote->cStickX1 = decrypt(dp[startByte]) & 0x3F; + wiiremote->cStickY1 = decrypt(dp[startByte + 1]) & 0x3F; + + wiiremote->cStickX2 = (((decrypt(dp[startByte +0]) & 0xC0) >> 3) | + ((decrypt(dp[startByte +1]) & 0xC0) >> 5) | + ((decrypt(dp[startByte +2]) & 0x80) >> 7)) & 0x1F; + wiiremote->cStickY2 = decrypt(dp[startByte + 2]) & 0x1F; + + wiiremote->cAnalogL = (((decrypt(dp[startByte +2]) & 0x60) >> 2) | + ((decrypt(dp[startByte +3]) & 0xE0) >> 5)) & 0x1F; + wiiremote->cAnalogR = decrypt(dp[startByte + 3]) & 0x1F; + } +} + +void handleIRData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + int i; + + if (dp[1] == 0x33) + { // 12 IR bytes + int startByte = 0; + for(i=0 ; i < 4 ; i++) + { + startByte = 7 + 3 * i; + wiiremote->irData[i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; + wiiremote->irData[i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; + wiiremote->irData[i].s = dp[startByte +2] & 0x0F; + } + } + else + { // 10 IR bytes + int shift = (dp[1] == 0x36) ? 4 : 7; + int startByte = 0; + for (i=0; i < 2; i++) { + startByte = shift + 5 * i; + wiiremote->irData[2*i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; + wiiremote->irData[2*i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; + wiiremote->irData[2*i].s = ((wiiremote->irData[2*i].x == wiiremote->irData[2*i].y) && (wiiremote->irData[2*i].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. + + wiiremote->irData[(2*i)+1].x = (dp[startByte +3] | ((dp[startByte +2] & 0x03) << 8)) & 0x3FF; + wiiremote->irData[(2*i)+1].y = (dp[startByte +4] | ((dp[startByte +2] & 0x0C) << 6)) & 0x3FF; + wiiremote->irData[(2*i)+1].s = ((wiiremote->irData[(2*i)+1].x == wiiremote->irData[(2*i)+1].y) && (wiiremote->irData[(2*i)+1].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. + } + } + + int p1 = -1; + int p2 = -1; + // we should modify this loop to take the points with the lowest s (the brightest ones) + for (i=0 ; i<4 ; i++) { + if (p1 == -1) { + if (wiiremote->irData [i].s < 0x0F) + p1 = i; + } else { + if (wiiremote->irData [i].s < 0x0F) { + p2 = i; + break; + } + } + } + + double ox, oy; + if ((p1 > -1) && (p2 > -1)) + { + int l = wiiremote->leftPoint; + if (wiiremote->leftPoint == -1) + { + switch (wiiremote->orientation) + { + case 0: l = (wiiremote->irData[p1].x < wiiremote->irData[p2].x) ? 0 : 1; break; + case 1: l = (wiiremote->irData[p1].y > wiiremote->irData[p2].y) ? 0 : 1; break; + case 2: l = (wiiremote->irData[p1].x > wiiremote->irData[p2].x) ? 0 : 1; break; + case 3: l = (wiiremote->irData[p1].y < wiiremote->irData[p2].y) ? 0 : 1; break; + } + + wiiremote->leftPoint = l; + } + + int r = 1-l; + + double dx = wiiremote->irData[r].x - wiiremote->irData[l].x; + double dy = wiiremote->irData[r].y - wiiremote->irData[l].y; + double d = hypot (dx, dy); + + dx /= d; + dy /= d; + + double cx = (wiiremote->irData[l].x + wiiremote->irData[r].x)/kWiiIRPixelsWidth - 1; + double cy = (wiiremote->irData[l].y + wiiremote->irData[r].y)/kWiiIRPixelsHeight - 1; + + ox = -dy*cy-dx*cx; + oy = -dx*cy+dy*cx; + + // cam: + // Compensate for distance. There must be fewer than 0.75*768 pixels between the spots for this to work. + // In other words, you have to be far enough away from the sensor bar for the two spots to have enough + // space on the image sensor to travel without one of the points going off the image. + // note: it is working very well ... + double gain = 4; + if (d < (0.75 * kWiiIRPixelsHeight)) + gain = 1 / (1 - d/kWiiIRPixelsHeight); + + ox *= gain; + oy *= gain; + + wiiremote->angle = atan2(dy, dx); + wiiremote->tracking = true; + } + else + { + ox = oy = -100; + wiiremote->leftPoint = -1; // not tracking + wiiremote->angle = -100; + wiiremote->tracking = false; + } + + wiiremote->posX = ox; + wiiremote->posY = oy; +} + +void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) +{ + // wiimote buttons + wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; + + // report contains extension data + switch (dp[1]) + { + case 0x34 : + case 0x35 : + case 0x36 : + case 0x37 : + handleExtensionData(wiiremote, dp, dataLength); + break; + } + + // report contains IR data + if (dp[1] & 0x02) + { + handleIRData(wiiremote, dp, dataLength); + } + + // report contains motion sensor data + if (dp[1] & 0x01) + { + wiiremote->accX = dp[4]; + wiiremote->accY = dp[5]; + wiiremote->accZ = dp[6]; + + wiiremote->lowZ = wiiremote->lowZ * 0.9 + wiiremote->accZ * 0.1; + wiiremote->lowX = wiiremote->lowX * 0.9 + wiiremote->accX * 0.1; + + float absx = abs(wiiremote->lowX-128); + float absz = abs(wiiremote->lowZ-128); + + if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; + if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; + + if (absz >= absx) + { + if (absz > 5) + wiiremote->orientation = (wiiremote->lowZ > 128)?0:2; + } + else + { + if (absx > 5) + wiiremote->orientation = (wiiremote->lowX > 128)?3:1; + } + } +} + +//-------------------------------------------------------------------------------------------- + + void myDataListener(IOBluetoothL2CAPChannelRef channel, void *dataPointer, UInt16 dataLength, void *refCon) +{ + WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; + unsigned char* dp = (unsigned char*)dataPointer; + + if (!wiiremote->device) + return; + + //controller status (expansion port and battery level data) - received when report 0x15 sent to Wiimote (getCurrentStatus:) or status of expansion port changes. + if (dp[1] == 0x20 && dataLength >= 8) + { + handleStatusReport(wiiremote, dp, dataLength); + requestUpdates(wiiremote); // Make sure we keep getting state change reports. + return; + } + + if (dp[1] == 0x21) + { + handleRAMData(wiiremote, dp, dataLength); + return; + } + + if (dp[1] == 0x22) + { // Write data response + //NSLog(@"Write data response: %00x %00x %00x %00x", dp[2], dp[3], dp[4], dp[5]); + return; + } + + // report contains button info + if ((dp[1] & 0xF0) == 0x30) + { + handleButtonReport(wiiremote, dp, dataLength); + } +} + +void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) +{ + if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) + { + // In thise case: + // event->u.newData.dataPtr is a pointer to the block of data received. + // event->u.newData.dataSize is the size of the block of data. + myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); + } + else + if (event->eventType == kIOBluetoothL2CAPChannelEventTypeClosed) + { + // In this case: + // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel + // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). + } +} + +void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) +{ + CFStringRef itsAddress, myAddress; + + itsAddress = IOBluetoothDeviceGetAddressString(objectRef); + if (itsAddress != nil) + { + myAddress = IOBluetoothDeviceGetAddressString(((WiiRemoteRef)refCon)->device); + if (myAddress != nil) + { + if (CFStringCompare(itsAddress, myAddress, 0) == kCFCompareEqualTo) + { + wiiremote_disconnect((WiiRemoteRef)refCon); + } + CFRelease(myAddress); + } + CFRelease(itsAddress); + } +} + +//-------------------------------------------------------------------------------------------- + +void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address) +{ + CFStringRef cfstring; + + cfstring = IOBluetoothDeviceGetAddressString(wiiremote->device); + CFStringGetCString(cfstring, address, 32, kCFStringEncodingMacRoman); + CFRelease(cfstring); + +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_connect(WiiRemoteRef wiiremote) +{ + IOReturn ret; + Boolean result; + short i; + + if (wiiremote->device == nil) + return false; + + // connect the device + for (i=0; idevice, nil, nil); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) + return false; + + wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, (void *)wiiremote); + + // performs an SDP query + for (i=0; idevice, nil, nil); + if ( ret == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + if (i==kTrial) + return false; + + result = openCChan(wiiremote); + result = openIChan(wiiremote); + + if (result) + { + result = wiiremote_led(wiiremote, wiiremote->isLED1Illuminated, wiiremote->isLED2Illuminated, wiiremote->isLED3Illuminated, wiiremote->isLED4Illuminated); + } + + if (result == false) + { + wiiremote_disconnect(wiiremote); + return result; + } + + wiiremote_getstatus(wiiremote); + requestUpdates(wiiremote); + + readData(wiiremote, 0x0020, 7); // Get Accelerometer callibration data + + return true; +} + + +Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) +{ + short i = 0; + + if (wiiremote->cchan) + { + if (IOBluetoothDeviceIsConnected(wiiremote->device)) + { + for (i=0; icchan) == kIOReturnSuccess) + break; + usleep(kWait); // wait 10ms + } + } + if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->cchan); + wiiremote->cchan = nil; + } + + if (wiiremote->ichan) + { + if (IOBluetoothDeviceIsConnected(wiiremote->device)) + { + for (i=0; iichan) == kIOReturnSuccess) + break; + } + } + if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->ichan); + wiiremote->ichan = nil; + } + + if (wiiremote->device) + { + if (IOBluetoothDeviceIsConnected(wiiremote->device)) + { + for (i=0; idevice) == kIOReturnSuccess) + break; + } + } + if (i==kTrial) return false; + IOBluetoothObjectRelease(wiiremote->device); + wiiremote->device = nil; + } + + if (wiiremote->disconnectNotification != nil) + { + IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); + wiiremote->disconnectNotification = nil; + } + + return true; +} + +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- + +Boolean requestUpdates(WiiRemoteRef wiiremote) +{ + Boolean result; + + // Set the report type the Wiimote should send. + unsigned char cmd[] = {0x12, 0x02, 0x30}; // Just buttons. + + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + + /* + There are numerous status report types that can be requested. + The IR reports must be matched with the data format set when initializing the IR camera: + 0x36, 0x37 - 10 IR bytes go with Basic mode + 0x33 - 12 IR bytes go with Extended mode + 0x3e/0x3f - 36 IR bytes go with Full mode + + The Nunchuk and Classic controller use 6 bytes to report their state, so the reports that + give more extension bytes don't provide any more info. + + Buttons | Accelerometer | IR | Extension + --------------------+-------------------+-----------+------------- + 0x30: Core Buttons | | | + 0x31: Core Buttons | Accelerometer | | + 0x32: Core Buttons | | | 8 bytes + 0x33: Core Buttons | Accelerometer | 12 bytes | + 0x34: Core Buttons | | | 19 bytes + 0x35: Core Buttons | Accelerometer | | 16 bytes + 0x36: Core Buttons | | 10 bytes | 9 bytes + 0x37: Core Buttons | Accelerometer | 10 bytes | 6 bytes + ?? 0x38: Core Buttons and Accelerometer with 16 IR bytes ?? + 0x3d: | | | 21 bytes + + 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 16/36 IR bytes + + */ + + if (wiiremote->isIRSensorEnabled) + { + if (wiiremote->isExpansionPortEnabled) + { + cmd[2] = 0x36; // Buttons, 10 IR Bytes, 9 Extension Bytes + wiiremote->wiiIRMode = kWiiIRModeBasic; + } + else + { + cmd[2] = 0x33; // Buttons, Accelerometer, and 12 IR Bytes. + wiiremote->wiiIRMode = kWiiIRModeExtended; + } + + // Set IR Mode + writeData(wiiremote, (darr){ wiiremote->wiiIRMode }, 0x04B00033, 1); + usleep(kWait); // wait 10ms + } + else + { + if (wiiremote->isExpansionPortEnabled) + { + cmd[2] = 0x34; // Buttons, 19 Extension Bytes + } + else + { + cmd[2] = 0x30; // Buttons + } + } + + if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; // Add Accelerometer + + usleep(kWait); // wait 10ms + result = sendCommand(wiiremote, cmd, 3); + + return(result); +} + +//-------------------------------------------------------------------------------------------- + +Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled) +{ + wiiremote->isMotionSensorEnabled = enabled; + return requestUpdates(wiiremote); +} + +Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled) +{ + + wiiremote->isVibrationEnabled = enabled; + return requestUpdates(wiiremote); +} + +Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) +{ + unsigned char cmd[] = {0x11, 0x00}; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (enabled1) cmd[1] |= 0x10; + if (enabled2) cmd[1] |= 0x20; + if (enabled3) cmd[1] |= 0x40; + if (enabled4) cmd[1] |= 0x80; + + wiiremote->isLED1Illuminated = enabled1; + wiiremote->isLED2Illuminated = enabled2; + wiiremote->isLED3Illuminated = enabled3; + wiiremote->isLED4Illuminated = enabled4; + + return sendCommand(wiiremote, cmd, 2); +} + +Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled) +{ + wiiremote->isExpansionPortEnabled = enabled; + if (wiiremote->isExpansionPortAttached == false) + { + wiiremote->isExpansionPortEnabled = false; + } + else + { + readData(wiiremote, 0x04A40020, 16); //get calbdata + } + + return requestUpdates(wiiremote); +} + +Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) +{ + Boolean ret; + + wiiremote->isIRSensorEnabled = enabled; + + // ir enable 1 + unsigned char cmd[] = {0x13, 0x00}; + if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; + if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; + if ((ret = sendCommand(wiiremote, cmd, 2)) == false) + return ret; + usleep(kWait); + + // set register 0x1a (ir enable 2) + unsigned char cmd2[] = {0x1a, 0x00}; + if (enabled) cmd2[1] |= 0x04; + if ((ret = sendCommand(wiiremote, cmd2, 2)) == false) + return ret; + usleep(kWait); + + if(enabled) + { + // based on marcan's method, found on wiili wiki: + // tweaked to include some aspects of cliff's setup procedure in the hopes + // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) + // the sleeps help it it seems + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xC0}, 0x04B00000, 9)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x40, 0x00}, 0x04B0001A, 2)) == false) return ret; + usleep(kWait); + if ((ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1)) == false) return ret; + usleep(kWait); + + requestUpdates(wiiremote); + } + else + { + // probably should do some writes to power down the camera, save battery + // but don't know how yet. + + ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); + ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); + ret = wiiremote_expansion(wiiremote, wiiremote->isExpansionPortEnabled); + } + + return ret; +} + +Boolean wiiremote_getstatus(WiiRemoteRef wiiremote) +{ + unsigned char cmd[] = {0x15, 0x00}; + return sendCommand(wiiremote, cmd, 2); +} + + diff --git a/aka.wiiremote/wiiremote.h b/aka.wiiremote/wiiremote.h new file mode 100644 index 0000000..4a03f09 --- /dev/null +++ b/aka.wiiremote/wiiremote.h @@ -0,0 +1,175 @@ +// wiiremote.h +// Copyright by Masayuki Akamatsu +// Based on "DarwiinRemote" by Hiroaki Kimura + +#include +#include +#include +#include +#include + +// Macros for PD for compability with Max macros +#ifdef PD +#define SETSYM SETSYMBOL +#define SETLONG SETFLOAT +#endif + +typedef unsigned char WiiIRModeType; +enum { + kWiiIRModeBasic = 0x01, + kWiiIRModeExtended = 0x03, + kWiiIRModeFull = 0x05 +}; + +typedef struct { + int x, y, s; +} IRData; + +typedef struct { + unsigned char accX_zero, accY_zero, accZ_zero, accX_1g, accY_1g, accZ_1g; +} WiiAccCalibData; + +typedef struct { + unsigned char x_min, x_max, x_center, y_min, y_max, y_center; +} WiiJoyStickCalibData; + +typedef UInt16 WiiButtonType; +enum { + WiiRemoteAButton, + WiiRemoteBButton, + WiiRemoteOneButton, + WiiRemoteTwoButton, + WiiRemoteMinusButton, + WiiRemoteHomeButton, + WiiRemotePlusButton, + WiiRemoteUpButton, + WiiRemoteDownButton, + WiiRemoteLeftButton, + WiiRemoteRightButton, + + WiiNunchukZButton, + WiiNunchukCButton, + + WiiClassicControllerXButton, + WiiClassicControllerYButton, + WiiClassicControllerAButton, + WiiClassicControllerBButton, + WiiClassicControllerLButton, + WiiClassicControllerRButton, + WiiClassicControllerZLButton, + WiiClassicControllerZRButton, + WiiClassicControllerUpButton, + WiiClassicControllerDownButton, + WiiClassicControllerLeftButton, + WiiClassicControllerRightButton, + WiiClassicControllerMinusButton, + WiiClassicControllerHomeButton, + WiiClassicControllerPlusButton +}; + +typedef UInt16 WiiExpansionPortType; +enum{ + WiiExpNotAttached, + WiiNunchuk, + WiiClassicController +}; + +typedef UInt16 WiiAccelerationSensorType; +enum{ + WiiRemoteAccelerationSensor, + WiiNunchukAccelerationSensor +}; + + +typedef UInt16 WiiJoyStickType; +enum{ + WiiNunchukJoyStick, + WiiClassicControllerLeftJoyStick, + WiiClassicControllerRightJoyStick +}; + + +typedef struct _WiiRemoteRec +{ + IOBluetoothDeviceInquiryRef inquiry; + IOBluetoothDeviceRef device; + IOBluetoothL2CAPChannelRef ichan; + IOBluetoothL2CAPChannelRef cchan; + + CFStringRef address; + + unsigned char accX; + unsigned char accY; + unsigned char accZ; + unsigned short buttonData; + + float lowZ; + float lowX; + int orientation; + int leftPoint; // is point 0 or 1 on the left. -1 when not tracking. + + float posX; + float posY; + float angle; + Boolean tracking; + + WiiExpansionPortType expType; + WiiAccCalibData wiiCalibData, nunchukCalibData; + WiiJoyStickCalibData nunchukJoyStickCalibData; + WiiIRModeType wiiIRMode; + IRData irData[4]; + double batteryLevel; + + Boolean readingRegister; + Boolean isMotionSensorEnabled; + Boolean isIRSensorEnabled; + Boolean isVibrationEnabled; + Boolean isExpansionPortEnabled; + Boolean initExpPort; + Boolean isLED1Illuminated; + Boolean isLED2Illuminated; + Boolean isLED3Illuminated; + Boolean isLED4Illuminated; + Boolean isExtraOutputEnabled; + + Boolean isExpansionPortAttached; + + IOBluetoothUserNotificationRef disconnectNotification; + + //nunchuk + unsigned char nStickX; + unsigned char nStickY; + unsigned char nAccX; + unsigned char nAccY; + unsigned char nAccZ; + unsigned char nButtonData; + + float nLowZ; + float nLowX; + int nOrientation; + + //classic controller + unsigned short cButtonData; + unsigned char cStickX1; + unsigned char cStickY1; + unsigned char cStickX2; + unsigned char cStickY2; + unsigned char cAnalogL; + unsigned char cAnalogR; + +} WiiRemoteRec, *WiiRemoteRef; + +void wiiremote_init(WiiRemoteRef wiiremote); +Boolean wiiremote_isconnected(WiiRemoteRef wiiremote); +Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address); +Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote); +Boolean wiiremote_connect(WiiRemoteRef wiiremote); +Boolean wiiremote_disconnect(WiiRemoteRef wiiremote); +void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address); +Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); +Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled); +Boolean wiiremote_getstatus(WiiRemoteRef wiiremote); + diff --git a/wiiremote/COPYRIGHT.txt b/wiiremote/COPYRIGHT.txt deleted file mode 100644 index b33233c..0000000 --- a/wiiremote/COPYRIGHT.txt +++ /dev/null @@ -1,13 +0,0 @@ -Max porting by Masayuki Akamatsu -Copyright (c) 2006, Masayuki Akamatsu -Based on "DarwiinRemote" by Hiroaki Kimura -Copyright (c) 2006, Hiroaki Kimura -All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/wiiremote/HISTORY.txt b/wiiremote/HISTORY.txt deleted file mode 100644 index a0687b1..0000000 --- a/wiiremote/HISTORY.txt +++ /dev/null @@ -1,54 +0,0 @@ -aka.wiiremote Version History - -1.0B6 : 2007.04.24 - -- The Classic Controller is supported. -- The help patch is updated. -- The URLs in [info] subpatch are updated. - -- 'expansion' message enables to use the expansion controller(Nunchuk or Classic Controller). -- 'nunchuk' message is obsolete. - You should use 'expansion' instead of it even though you can use it for the backward compatibility only. - -- The IR sensor and the expansion controller (ex. Nunchuk) can be used together. - -- The stability on PPC-Mac is a little improved. - You have to do the following steps every time you use the Wii Remote on PPC-Mac. - (You would set up only once on Intel-Mac.) -1: Delete "Nintendo RVL-CNT-01" on "Device" tab in "Bluetooth" System Preference. -2: Do the setup for Wii Remote. See http://max.iamas.ac.jp/2061/articles/121.html -3: Open "aka.wiiremote.help" and connect it. - - -1.0B5 : 2007.02.03 - -- Nunchuk is supported. -( Classic Controller is NOT supported.) -- device address is supported. -- outlets and output messages are changed. -- some input messages are simplified. -- help patch is expanded for Nunchuk. - - -1.0B4 : 2006.12.24 - -- multiple Wii remotes are supported. - - -1.0B3 : 2006.12.20 - -- data acquisition is improved. -- unusual vibration sound is resolved. - - -1.0B2 : 2006.12.15 - -- connection/disconnection is improved. -- IR sensor is supported. -- status report is supported -- help patch is rewritten. - - -1.0B1 : 2006.12.12 - -- first release \ No newline at end of file diff --git a/wiiremote/Makefile b/wiiremote/Makefile deleted file mode 100644 index e222c9b..0000000 --- a/wiiremote/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') -EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') - -default: - make -C $(EXTERNALS_ROOT) $(TARGET) - -install: - make -C $(EXTERNALS_ROOT) $(TARGET)_install - -clean: - make -C $(EXTERNALS_ROOT) $(TARGET)_clean - -test_locations: - make -C $(EXTERNALS_ROOT) test_locations - -# for emacs -etags: - etags ../../../pd/src/*.h *.[ch] - make etags_`uname -s` - -etags_Darwin: - etags -a \ - /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \ - /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \ - /System/Library/Frameworks/Carbon.framework/Headers/*.h \ - /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[ch] - -etags_Linux: - etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: - etags -a /usr/include/*.h /usr/include/sys/*.h \ - /usr/local/include/*.h /usr/local/include/sys/*.h diff --git a/wiiremote/README.txt b/wiiremote/README.txt deleted file mode 100644 index bdaf778..0000000 --- a/wiiremote/README.txt +++ /dev/null @@ -1,6 +0,0 @@ - -This is a port of the Max class aka.wiiremote by Masayuki Akamatsu. Its -available here: - -http://www.iamas.ac.jp/~aka/max/#aka_wiiremote - diff --git a/wiiremote/TODO b/wiiremote/TODO deleted file mode 100644 index a8da43d..0000000 --- a/wiiremote/TODO +++ /dev/null @@ -1,7 +0,0 @@ - - - - try out IOBluetoothLocalDeviceAvailable(wiiremote->inquiry); to see if that will set up the event loops (http://lists.apple.com/archives/bluetooth-dev/2006/Dec/msg00001.html) - - -- try CFRunLoopRun(); then CFRunLoopStop(CFRunLoopGetCurrent()); in akawiiremote_clock() and akawiiremote_bang() - diff --git a/wiiremote/aka.wiiremote.c b/wiiremote/aka.wiiremote.c deleted file mode 100644 index 767d737..0000000 --- a/wiiremote/aka.wiiremote.c +++ /dev/null @@ -1,642 +0,0 @@ -// aka.wiiremote.c -// Copyright by Masayuki Akamatsu -// Code for PD by Hans-Christoph Steiner -// 1.0B1 : 2006.12.12 -// 1.0B2 : 2006.12.15 -// 1.0B3 : 2006.12.20 -// 1.0B4 : 2006.12.24 -// 1.0B5 : 2007.02.03 -// 1.0B6 : 2007.04.24 - -#ifdef PD -#include "m_pd.h" -#define SETSYM SETSYMBOL -#define SETLONG SETFLOAT -#define method t_method -//#define addbang(x) class_addbang(wiiremote_class, (x)) -//#define addmess(x) class_addmessage(class_wiiremote, (x)) -static t_class *wiiremote_class; -#else /* Max */ -#include "ext.h" -#endif /* PD */ - -#include "wiiremote.h" -#include -#include - -#define kInterval 100 -#define kMaxTrial 100 - -typedef struct _akawiiremote -{ -#ifdef PD - t_object x_obj; -#else /* Max */ - struct object obj; -#endif - - WiiRemoteRef wiiremote; - char address[32]; - - void *clock; - Boolean connected; - - void *statusOut; - void *dataOut; -} t_akawiiremote; - -void *akawiiremote_class; // the number of instance of this object - -void akawiiremote_bang(t_akawiiremote *x); -void akawiiremote_address(t_akawiiremote *x, t_symbol *s); -void akawiiremote_connect(t_akawiiremote *x); -void akawiiremote_disconnect(t_akawiiremote *x); -void akawiiremote_motionsensor(t_akawiiremote *x, long enable); -void akawiiremote_irsensor(t_akawiiremote *x, long enable); -void akawiiremote_vibration(t_akawiiremote *x, long enable); -void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4); -void akawiiremote_expansion(t_akawiiremote *x, long enable); -void akawiiremote_extraoutput(t_akawiiremote *x, long enable); - -void akawiiremote_getbattery(t_akawiiremote *x); -void akawiiremote_getexpansion(t_akawiiremote *x); -void akawiiremote_getled(t_akawiiremote *x); -void akawiiremote_getaddress(t_akawiiremote *x); -void akawiiremote_getcalibration(t_akawiiremote *x); - -void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s); -void akawiiremote_clock(t_akawiiremote *x); -void *akawiiremote_new(t_symbol *s, short ac, t_atom *av); -void akawiiremote_free(t_akawiiremote *x); - -char remoteStr[] = "remote"; -char nunchukStr[] = "nunchuk"; -char classicStr[] = "classic"; - -#ifdef PD -void wiiremote_setup() -#else /* Max */ -void main() -#endif /* PD */ -{ - NumVersion outSoftwareVersion; - BluetoothHCIVersionInfo outHardwareVersion; - - post("aka.wiiremote 1.0B7-UB by Masayuki Akamatsu"); - - if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) // B7 - { - if (outSoftwareVersion.majorRev < 1 && outSoftwareVersion.minorAndBugRev < 0x63) - { - error("requires Blutooth version 1.6.3 or later."); - return; - } - } - else - { - error("can't get Bluetooth version."); - return; - } - -#ifdef PD - post("\tPd port by Hans-Christoph Steiner"); - - wiiremote_class = class_new(gensym("wiiremote"), - (t_newmethod)akawiiremote_new, - (t_method)akawiiremote_free, - sizeof(t_akawiiremote), - CLASS_DEFAULT, - A_GIMME,0); - - class_addbang(wiiremote_class,(t_method)akawiiremote_bang); - class_addmethod(wiiremote_class,(t_method)akawiiremote_address,gensym("address"),A_DEFSYMBOL, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("expansion"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("nunchuk"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_extraoutput,gensym("extraoutput"), A_DEFFLOAT, 0); // B7 - - class_addmethod(wiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getaddress,gensym("getaddress"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getcalibration,gensym("getcalibration"), 0); -#else /* Max */ - setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); - - addbang((method)akawiiremote_bang); - addmess((method)akawiiremote_address,"address",A_DEFSYM, 0); - addmess((method)akawiiremote_connect,"connect", 0); - addmess((method)akawiiremote_disconnect,"disconnect",0); - addmess((method)akawiiremote_motionsensor,"motion", A_DEFLONG, 0); - addmess((method)akawiiremote_irsensor,"ir", A_DEFLONG, 0); - addmess((method)akawiiremote_vibration,"vibration", A_DEFLONG, 0); - addmess((method)akawiiremote_led,"led", A_DEFLONG, A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); - addmess((method)akawiiremote_expansion,"expansion", A_DEFLONG, 0); - addmess((method)akawiiremote_expansion,"nunchuk", A_DEFLONG, 0); - addmess((method)akawiiremote_extraoutput,"extraoutput", A_DEFLONG, 0); // B7 - - addmess((method)akawiiremote_getbattery,"getbattery",0); - addmess((method)akawiiremote_getexpansion,"getexpansion",0); - addmess((method)akawiiremote_getled,"getled",0); - addmess((method)akawiiremote_getaddress,"getaddress",0); - addmess((method)akawiiremote_getcalibration,"getcalibration", 0); - - addmess((method)akawiiremote_assist,"assist",A_CANT,0); -#endif /* PD */ -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_bang(t_akawiiremote *x) -{ - t_atom av[7]; - - if (x->wiiremote->device == nil) - return; // do nothing - - if (x->wiiremote->isExpansionPortAttached && x->wiiremote->isExpansionPortEnabled) - { - // Classic Controller - if (x->wiiremote->expType == WiiClassicController) - { - // Buttons - SETSYM(av, gensym("buttons")); - SETLONG(av + 1, x->wiiremote->cButtonData); - outlet_anything(x->dataOut, gensym(classicStr), 2, av); - - // Joystick 1 - SETSYM(av, gensym("stick1")); - SETLONG(av + 1, x->wiiremote->cStickX1); - SETLONG(av + 2, x->wiiremote->cStickY1); - outlet_anything(x->dataOut, gensym(classicStr), 3, av); - - // Joystick 2 - SETSYM(av, gensym("stick2")); - SETLONG(av + 1, x->wiiremote->cStickX2); - SETLONG(av + 2, x->wiiremote->cStickY2); - outlet_anything(x->dataOut, gensym(classicStr), 3, av); - - // Analog - SETSYM(av, gensym("analog")); - SETLONG(av + 1, x->wiiremote->cAnalogL); - SETLONG(av + 2, x->wiiremote->cAnalogR); - outlet_anything(x->dataOut, gensym(classicStr), 3, av); - } - - // Nunchuk - if (x->wiiremote->expType == WiiNunchuk) - { - // Buttons - SETSYM(av, gensym("buttons")); - SETLONG(av + 1, x->wiiremote->nButtonData); - outlet_anything(x->dataOut, gensym(nunchukStr), 2, av); - - // Joystick - SETSYM(av, gensym("stick")); - SETLONG(av + 1, x->wiiremote->nStickX); - SETLONG(av + 2, x->wiiremote->nStickY); - outlet_anything(x->dataOut, gensym(nunchukStr), 3, av); - - if (x->wiiremote->isExtraOutputEnabled) - { - SETSYM(av, gensym("stick_calibration")); - SETLONG(av + 1, x->wiiremote->nunchukJoyStickCalibData.x_min); - SETLONG(av + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); - SETLONG(av + 3, x->wiiremote->nunchukJoyStickCalibData.x_center); - SETLONG(av + 4, x->wiiremote->nunchukJoyStickCalibData.y_min); - SETLONG(av + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); - SETLONG(av + 6, x->wiiremote->nunchukJoyStickCalibData.y_center); - outlet_anything(x->dataOut, gensym(nunchukStr), 7, av); - } - - // Motion Sensor - if (x->wiiremote->isMotionSensorEnabled) - { - SETSYM(av, gensym("motion")); - SETLONG(av + 1, x->wiiremote->nAccX); - SETLONG(av + 2, x->wiiremote->nAccY); - SETLONG(av + 3, x->wiiremote->nAccZ); - SETLONG(av + 4, x->wiiremote->nOrientation); - outlet_anything(x->dataOut, gensym(nunchukStr), 5, av); - - if (x->wiiremote->isExtraOutputEnabled) - { - SETSYM(av, gensym("motion_calibration")); - SETLONG(av + 1, x->wiiremote->nunchukCalibData.accX_zero); - SETLONG(av + 2, x->wiiremote->nunchukCalibData.accY_zero); - SETLONG(av + 3, x->wiiremote->nunchukCalibData.accZ_zero); - SETLONG(av + 4, x->wiiremote->nunchukCalibData.accX_1g); - SETLONG(av + 5, x->wiiremote->nunchukCalibData.accY_1g); - SETLONG(av + 6, x->wiiremote->nunchukCalibData.accZ_1g); - outlet_anything(x->dataOut, gensym(nunchukStr), 7, av); - } - } - } - } - - // Wii Remote - - // Buttons - SETSYM(av, gensym("buttons")); - SETLONG(av + 1, x->wiiremote->buttonData); - outlet_anything(x->dataOut, gensym(remoteStr), 2, av); - - // IR Sensor - if (x->wiiremote->isIRSensorEnabled) - { - SETSYM(av, gensym("ir")); - SETFLOAT(av + 1, x->wiiremote->posX); // posX and posY are "float"???? - SETFLOAT(av + 2, x->wiiremote->posY); - SETFLOAT(av + 3, x->wiiremote->angle); - SETLONG (av + 4, x->wiiremote->tracking); - outlet_anything(x->dataOut, gensym(remoteStr), 5, av); - - if (x->wiiremote->isExtraOutputEnabled) // B7 - { - SETSYM(av, gensym("irraw")); - SETLONG(av + 1, 0); - SETLONG(av + 2, x->wiiremote->irData[0].x); - SETLONG(av + 3, x->wiiremote->irData[0].y); - SETLONG(av + 4, x->wiiremote->irData[0].s); - outlet_anything(x->dataOut, gensym(remoteStr), 5, av); - SETLONG(av + 1, 1); - SETLONG(av + 2, x->wiiremote->irData[1].x); - SETLONG(av + 3, x->wiiremote->irData[1].y); - SETLONG(av + 4, x->wiiremote->irData[1].s); - outlet_anything(x->dataOut, gensym(remoteStr), 5, av); - SETLONG(av + 1, 2); - SETLONG(av + 2, x->wiiremote->irData[2].x); - SETLONG(av + 3, x->wiiremote->irData[2].y); - SETLONG(av + 4, x->wiiremote->irData[2].s); - outlet_anything(x->dataOut, gensym(remoteStr), 5, av); - SETLONG(av + 1, 3); - SETLONG(av + 2, x->wiiremote->irData[3].x); - SETLONG(av + 3, x->wiiremote->irData[3].y); - SETLONG(av + 4, x->wiiremote->irData[3].s); - outlet_anything(x->dataOut, gensym(remoteStr), 5, av); - } - } - - // Motion Sensor - if (x->wiiremote->isMotionSensorEnabled) - { - SETSYM(av, gensym("motion")); - SETLONG(av + 1, x->wiiremote->accX); - SETLONG(av + 2, x->wiiremote->accY); - SETLONG(av + 3, x->wiiremote->accZ); - SETLONG(av + 4, x->wiiremote->orientation); - outlet_anything(x->dataOut, gensym(remoteStr), 5, av); - - if (x->wiiremote->isExtraOutputEnabled) // B7 - { - SETSYM(av, gensym("motion_calibration")); - SETLONG(av + 1, x->wiiremote->wiiCalibData.accX_zero); - SETLONG(av + 2, x->wiiremote->wiiCalibData.accY_zero); - SETLONG(av + 3, x->wiiremote->wiiCalibData.accZ_zero); - SETLONG(av + 4, x->wiiremote->wiiCalibData.accX_1g); - SETLONG(av + 5, x->wiiremote->wiiCalibData.accY_1g); - SETLONG(av + 6, x->wiiremote->wiiCalibData.accZ_1g); - outlet_anything(x->dataOut, gensym(remoteStr), 7, av); - } - } -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_address(t_akawiiremote *x, t_symbol *s) -{ - if (*(s->s_name) == 0) // if null string - *(x->address) = 0; - else - strcpy(x->address, s->s_name); -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_connect(t_akawiiremote *x) -{ - post("akawiiremote_connect"); - t_atom status; - Boolean result; - - if (wiiremote_isconnected(x->wiiremote)) - { - SETLONG(&status, -1); - outlet_anything(x->statusOut, gensym("connect"), 1, &status); - } - else - { - result = wiiremote_search(x->wiiremote, x->address); // start searching the device - x->connected = false; - clock_unset(x->clock); // stop clock - clock_delay(x->clock, 0); // start clock to check the device found - } -} - -void akawiiremote_foundFunc(t_akawiiremote *x) -{ -} - -void akawiiremote_disconnect(t_akawiiremote *x) -{ - post("akawiiremote_disconnect"); - - Boolean result; - t_atom status; - - clock_unset(x->clock); // stop clock - wiiremote_stopsearch(x->wiiremote); - - result = wiiremote_disconnect(x->wiiremote); - SETLONG(&status, result); - outlet_anything(x->statusOut, gensym("disconnect"), 1, &status); - - x->connected = !result; -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_motionsensor(t_akawiiremote *x, long enable) -{ - Boolean result; - - result = wiiremote_motionsensor(x->wiiremote, enable); - //SETLONG(&status, result); - //outlet_anything(x->statusOut, gensym("motion"), 1, &status); -} - -void akawiiremote_irsensor(t_akawiiremote *x, long enable) -{ - Boolean result; - - result = wiiremote_irsensor(x->wiiremote, enable); - //SETLONG(&status, result); - //outlet_anything(x->statusOut, gensym("ir"), 1, &status); -} - -void akawiiremote_extraoutput(t_akawiiremote *x, long enable) // B7 -{ - x->wiiremote->isExtraOutputEnabled = enable; -} - -void akawiiremote_expansion(t_akawiiremote *x, long enable) -{ - Boolean result; - - result = wiiremote_expansion(x->wiiremote, enable); - //SETLONG(&status, result); - //outlet_anything(x->statusOut, gensym("nunchuk"), 1, &status); -} - -void akawiiremote_vibration(t_akawiiremote *x, long enable) -{ - Boolean result; - - result = wiiremote_vibration(x->wiiremote, enable); - //SETLONG(&status, result); - //outlet_anything(x->statusOut, gensym("vibration"), 1, &status); -} - -void akawiiremote_led(t_akawiiremote *x, long enable1, long enable2, long enable3, long enable4) -{ - Boolean result; - - result = wiiremote_led(x->wiiremote, enable1, enable2, enable3, enable4); - //SETLONG(&status, result); - //outlet_anything(x->statusOut, gensym("led"), 1, &status); -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_getbattery(t_akawiiremote *x) -{ - if (x->wiiremote->device == nil) - { - outlet_anything(x->statusOut, gensym("battery"), 0, nil); - } - else - { - t_atom status; - - SETFLOAT(&status, x->wiiremote->batteryLevel); - outlet_anything(x->statusOut, gensym("battery"), 1, &status); - } -} - -void akawiiremote_getexpansion(t_akawiiremote *x) -{ - if (x->wiiremote->device == nil) - { - outlet_anything(x->statusOut, gensym("expansion"), 0, nil); - } - else - { - t_atom status; - if (x->wiiremote->isExpansionPortAttached) - SETLONG(&status, x->wiiremote->expType); - else - SETLONG(&status, 0); - outlet_anything(x->statusOut, gensym("expansion"), 1, &status); - } -} - -void akawiiremote_getled(t_akawiiremote *x) -{ - if (x->wiiremote->device == nil) - { - outlet_anything(x->statusOut, gensym("led"), 0, nil); - } - else - { - t_atom list[4]; - - SETLONG(list, x->wiiremote->isLED1Illuminated); - SETLONG(list + 1, x->wiiremote->isLED2Illuminated); - SETLONG(list + 2, x->wiiremote->isLED3Illuminated); - SETLONG(list + 3, x->wiiremote->isLED4Illuminated); - outlet_anything(x->statusOut, gensym("led"), 4, list); - } -} - -void akawiiremote_getcalibration(t_akawiiremote *x) -{ - if (x->wiiremote->device == nil) - { - outlet_anything(x->statusOut, gensym("calibration"), 0, nil); - } - else - { - t_atom list[8]; - - if (x->wiiremote->isExpansionPortAttached) - { - SETSYM(list, gensym(nunchukStr)); - SETSYM(list + 1, gensym("stick")); - SETLONG(list + 2, x->wiiremote->nunchukJoyStickCalibData.x_max); - SETLONG(list + 3, x->wiiremote->nunchukJoyStickCalibData.x_min); - SETLONG(list + 4, x->wiiremote->nunchukJoyStickCalibData.x_center); - SETLONG(list + 5, x->wiiremote->nunchukJoyStickCalibData.y_max); - SETLONG(list + 6, x->wiiremote->nunchukJoyStickCalibData.y_min); - SETLONG(list + 7, x->wiiremote->nunchukJoyStickCalibData.y_center); - outlet_anything(x->statusOut, gensym("calibration"), 8, list); - - SETSYM(list + 1, gensym("motion")); - SETLONG(list + 2, x->wiiremote->nunchukCalibData.accX_zero); - SETLONG(list + 3, x->wiiremote->nunchukCalibData.accY_zero); - SETLONG(list + 4, x->wiiremote->nunchukCalibData.accZ_zero); - SETLONG(list + 5, x->wiiremote->nunchukCalibData.accX_1g); - SETLONG(list + 6, x->wiiremote->nunchukCalibData.accY_1g); - SETLONG(list + 7, x->wiiremote->nunchukCalibData.accZ_1g); - outlet_anything(x->statusOut, gensym("calibration"), 8, list); - } - - SETSYM(list, gensym(remoteStr)); - SETSYM(list + 1, gensym("motion")); - SETLONG(list + 2, x->wiiremote->wiiCalibData.accX_zero); - SETLONG(list + 3, x->wiiremote->wiiCalibData.accY_zero); - SETLONG(list + 4, x->wiiremote->wiiCalibData.accZ_zero); - SETLONG(list + 5, x->wiiremote->wiiCalibData.accX_1g); - SETLONG(list + 6, x->wiiremote->wiiCalibData.accY_1g); - SETLONG(list + 7, x->wiiremote->wiiCalibData.accZ_1g); - outlet_anything(x->statusOut, gensym("calibration"), 8, list); - } -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_getaddress(t_akawiiremote *x) -{ - if (x->wiiremote->device == nil) - { - outlet_anything(x->statusOut, gensym("address"), 0, nil); - } - else - { - char str[32]; - t_atom address; - - wiiremote_getaddress(x->wiiremote, str); - SETSYM(&address, gensym(str)); - outlet_anything(x->statusOut, gensym("address"), 1, &address); - } -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_clock(t_akawiiremote *x) -{ - Boolean connection; - t_atom status; - - connection = wiiremote_isconnected(x->wiiremote); - - if (x->connected == false && connection == true) // if the device is connected... - { - wiiremote_getstatus(x->wiiremote); - x->connected = true; - SETLONG(&status, 1); - outlet_anything(x->statusOut, gensym("connect"), 1, &status); - } - - if (x->connected == true && connection == false) - { - x->connected = false; - SETLONG(&status, 0); - outlet_anything(x->statusOut, gensym("connect"), 1, &status); - } - - clock_delay(x->clock, kInterval); // restart clock -} - -//-------------------------------------------------------------------------------------------- - -void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) -{ -#ifndef PD /* Max */ - if (m==ASSIST_INLET) - { - sprintf(s,"connect, bang, disconnect...."); - } - else -#endif /* NOT PD */ - { - switch(a) - { - case 0: sprintf(s,"data messages"); break; - case 2: sprintf(s,"status messages"); break; - } - } -} - -//-------------------------------------------------------------------------------------------- - -void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) -{ -#ifdef PD - t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); - t_symbol *first_argument; - - x->statusOut = outlet_new(&x->x_obj, 0); - x->dataOut = outlet_new(&x->x_obj, &s_list); - -/* this sets the device name from the object arguments */ - first_argument = atom_getsymbolarg(0, ac, av); - if(first_argument != &s_) - atom_string(av, x->address, MAXPDSTRING-1); -#else /* Max */ - t_akawiiremote *x; - - x = (t_akawiiremote *)newobject(akawiiremote_class); - - x->statusOut = outlet_new(x, 0); - x->dataOut = outlet_new(x, 0); - - if (ac>0 && av[0].a_type == A_SYM) - strcpy(x->address, av[0].a_w.w_sym->s_name); -#endif /* PD */ - - x->wiiremote = (WiiRemoteRef)getbytes(sizeof(WiiRemoteRec)); - if (x->wiiremote != nil) - { - wiiremote_init(x->wiiremote); - x->wiiremote->isMotionSensorEnabled = true; - x->wiiremote->isIRSensorEnabled = false; - x->wiiremote->isVibrationEnabled = false; - x->wiiremote->isExpansionPortEnabled = false; - x->wiiremote->isLED1Illuminated = false; - x->wiiremote->isLED2Illuminated = false; - x->wiiremote->isLED3Illuminated = false; - x->wiiremote->isLED4Illuminated = false; - x->wiiremote->isExtraOutputEnabled = false; - } - - x->clock = clock_new(x, (method)akawiiremote_clock); - - x->connected = false; - - return x; -} - -void akawiiremote_free(t_akawiiremote *x) -{ - if (x->wiiremote != nil) - { - if (wiiremote_isconnected(x->wiiremote)) - wiiremote_disconnect(x->wiiremote); - freebytes(x->wiiremote, sizeof(WiiRemoteRec)); - x->wiiremote = nil; - } - - clock_unset(x->clock); -#ifdef PD - clock_free(x->clock); -#else /* Max */ - freeobject((t_object *)x->clock); -#endif /* PD */ -} - diff --git a/wiiremote/wiiremote-help.pd b/wiiremote/wiiremote-help.pd deleted file mode 100644 index 5c8f610..0000000 --- a/wiiremote/wiiremote-help.pd +++ /dev/null @@ -1,80 +0,0 @@ -#N canvas 287 96 744 626 10; -#X msg 128 207 connect; -#X msg 141 228 disconnect; -#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 127 285 metro 100; -#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 89 283 bang; -#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote -with your computer (only required for the first use).; -#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs -will start blinking.; -#X text 49 109 - Click on the [connect( message \, the LEDs will stop -blinking once its connected; -#X text 49 139 - Start the [metro] to get updates from [wiiremote] -; -#X obj 399 526 pddp/print; -#X obj 354 556 pddp/print; -#X obj 354 410 route remote; -#X msg 503 290 getbattery; -#X msg 503 310 getled; -#X msg 503 330 getexpansion; -#X obj 489 431 print RIGHT; -#X obj 253 430 print LEFT; -#X obj 354 476 route motion buttons ir; -#X obj 444 497 pddp/print; -#X msg 294 224 ir \$1; -#X msg 218 225 motion \$1; -#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 344 224 vibration \$1; -#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 434 224 expansion \$1; -#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 524 223 extraoutput \$1; -#N canvas 254 342 450 300 address 0; -#X obj 176 252 outlet; -#X msg 206 126 getaddress; -#X msg 176 72 address 00-1e-35-4c-e6-f1; -#X connect 1 0 0 0; -#X connect 2 0 0 0; -#X restore 25 462 pd address; -#X msg 503 352 getaddress; -#X obj 631 536 dac~; -#X obj 632 408 pddp/dsp; -#X obj 640 500 osc~ 100; -#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1; -#X connect 0 0 34 0; -#X connect 1 0 34 0; -#X connect 2 0 22 0; -#X connect 3 0 21 0; -#X connect 4 0 34 0; -#X connect 5 0 4 0; -#X connect 6 0 34 0; -#X connect 13 0 19 0; -#X connect 13 1 17 0; -#X connect 14 0 34 0; -#X connect 15 0 34 0; -#X connect 16 0 34 0; -#X connect 19 0 12 0; -#X connect 19 1 11 0; -#X connect 19 2 20 0; -#X connect 21 0 34 0; -#X connect 22 0 34 0; -#X connect 23 0 24 0; -#X connect 24 0 34 0; -#X connect 25 0 26 0; -#X connect 26 0 34 0; -#X connect 27 0 28 0; -#X connect 28 0 34 0; -#X connect 30 0 34 0; -#X connect 33 0 31 0; -#X connect 33 0 31 1; -#X connect 34 0 18 0; -#X connect 34 1 13 0; diff --git a/wiiremote/wiiremote.c b/wiiremote/wiiremote.c deleted file mode 100644 index 481085e..0000000 --- a/wiiremote/wiiremote.c +++ /dev/null @@ -1,1087 +0,0 @@ -// wiiremote.c -// Copyright by Masayuki Akamatsu -// Based on "DarwiinRemote" by Hiroaki Kimura - -#include "wiiremote.h" -#include - -// this type is used a lot (data array): -typedef unsigned char darr[]; - -#define kTrial 10 -#define kWait 10000 -// the unit of kWait is microseconds, thus 10000 means 10ms - -#define kWiiIRPixelsWidth 1024.0 -#define kWiiIRPixelsHeight 768.0 - - -Boolean requestUpdates(WiiRemoteRef wiiremote); -void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event); - - -//-------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------- - -void wiiremote_init(WiiRemoteRef wiiremote) -{ - wiiremote->inquiry = nil; - wiiremote->device = nil; - wiiremote->ichan = nil; - wiiremote->cchan = nil; - - wiiremote->address = nil; - - wiiremote->accX = 0x10; - wiiremote->accY = 0x10; - wiiremote->accZ = 0x10; - wiiremote->buttonData = 0; - - wiiremote->lowZ = 0; - wiiremote->lowX = 0; - wiiremote->leftPoint = -1; - wiiremote->tracking = false; - - wiiremote->batteryLevel = 0; - - wiiremote->readingRegister = false; - wiiremote->isMotionSensorEnabled = false; - wiiremote->isVibrationEnabled = false; - wiiremote->isIRSensorEnabled = false; - wiiremote->wiiIRMode = kWiiIRModeExtended; - wiiremote->isExpansionPortEnabled = false; - wiiremote->isExpansionPortAttached = false; - wiiremote->expType = WiiExpNotAttached; - - wiiremote->isLED1Illuminated = false; - wiiremote->isLED2Illuminated = false; - wiiremote->isLED3Illuminated = false; - wiiremote->isLED4Illuminated = false; - - wiiremote->nAccX = 0x10; - wiiremote->nAccY = 0x10; - wiiremote->nAccZ = 0x10; - wiiremote->nButtonData = 0; - - wiiremote->nLowZ = 0; - wiiremote->nLowX = 0; - -} - -//-------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------- - -Boolean openCChan(WiiRemoteRef wiiremote) -{ - short i; - IOReturn ret; - - // open L2CAPChannel : BluetoothL2CAPPSM = 17 - for (i=0; idevice, &(wiiremote->cchan), 17, myEventListener, (void *)wiiremote); - if ( ret == kIOReturnSuccess) - break; - usleep(kWait); // wait 10ms - } - if (i==kTrial) - { - wiiremote->cchan = nil; - IOBluetoothDeviceCloseConnection(wiiremote->device); - return false; - } - IOBluetoothObjectRetain(wiiremote->cchan); - - return (ret==kIOReturnSuccess); -} - -Boolean openIChan(WiiRemoteRef wiiremote) -{ - short i; - IOReturn ret; - - // open L2CAPChannel : BluetoothL2CAPPSM = 19 - for (i=0; idevice, &(wiiremote->ichan), 19, myEventListener, (void *)wiiremote); - if ( ret == kIOReturnSuccess) - break; - usleep(kWait); // wait 10ms - } - if (i==kTrial) - { - wiiremote->ichan = nil; - IOBluetoothL2CAPChannelCloseChannel(wiiremote->cchan); - IOBluetoothObjectRelease(wiiremote->cchan); - IOBluetoothDeviceCloseConnection(wiiremote->device); - return false; - } - IOBluetoothObjectRetain(wiiremote->ichan); - - return (ret==kIOReturnSuccess); -} - -//-------------------------------------------------------------------------------------------- - -Boolean sendCommand(WiiRemoteRef wiiremote, unsigned char *data, unsigned short length) -{ - unsigned char buf[40]; - IOReturn ret; - int i; - - memset(buf,0,40); - buf[0] = 0x52; - memcpy(buf+1, data, length); - if (buf[1] == 0x16) - length=23; - else - length++; - - usleep(kWait); // wait 10ms // Done to make sure commands don't happen too fast. - - for (i = 0; icchan, buf, length); - if (ret == kIOReturnSuccess) - break; - usleep(kWait); - } - - if (ret != kIOReturnSuccess) - wiiremote_disconnect(wiiremote); - - return (ret==kIOReturnSuccess); -} - -Boolean writeData(WiiRemoteRef wiiremote, const unsigned char *data, unsigned long address, unsigned short length) -{ - unsigned char cmd[22]; - int i; - unsigned long addr = address; - - - for(i=0 ; i>24) & 0xFF; - cmd[2] = (addr>>16) & 0xFF; - cmd[3] = (addr>> 8) & 0xFF; - cmd[4] = (addr>> 0) & 0xFF; - cmd[5] = length; - - // and of course the vibration flag, as usual - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - - data = cmd; - - return sendCommand(wiiremote, cmd, 22); -} - -Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short length) -{ - - unsigned char cmd[7]; - unsigned long addr = address; - unsigned short len = length; - - cmd[0] = 0x17; - cmd[1] = (addr>>24)&0xFF; - cmd[2] = (addr>>16)&0xFF; - cmd[3] = (addr>> 8)&0xFF; - cmd[4] = (addr>> 0)&0xFF; - - cmd[5] = (len >> 8)&0xFF; - cmd[6] = (len >> 0)&0xFF; - - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (cmd[1] & 0x02) wiiremote->readingRegister = true; - - return sendCommand(wiiremote, cmd, 7); -} - -//-------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------- - -void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) -{ - post("checkDevice"); - CFStringRef name; - CFStringRef address; - - if (wiiremote_isconnected(wiiremote)) - return; - - name = IOBluetoothDeviceGetName(device); - address = IOBluetoothDeviceGetAddressString(device); - if (name != nil && address != nil) - { - if (CFStringCompare(name, CFSTR("Nintendo RVL-CNT-01"), 0) == kCFCompareEqualTo) - { - if ( CFStringGetLength(wiiremote->address) == 0 - || CFStringCompare(address, wiiremote->address, kCFCompareCaseInsensitive) == kCFCompareEqualTo) - { - wiiremote->device = IOBluetoothObjectRetain(device); - if ( wiiremote_connect(wiiremote) == false ) - wiiremote_disconnect(wiiremote); - } - } - } -} - -void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) -{ - post("myFoundFunc"); - checkDevice((WiiRemoteRef)refCon, device); -} - -void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) -{ - post("myUpdatedFunc"); - - checkDevice((WiiRemoteRef)refCon, device); -} - -void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) -{ - post("myCompleteFunc"); - - if (aborted) return; // called by stop ;) - - if (error != kIOReturnSuccess) - { - wiiremote_stopsearch((WiiRemoteRef)refCon); - return; - } -#ifdef PD - // PD doesn't use the Carbon loop, so we have to manually control it - CFRunLoopStop( CFRunLoopGetCurrent() ); -#endif -} - -//-------------------------------------------------------------------------------------------- - -Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) -{ - Boolean result; - - result = wiiremote->device != nil && IOBluetoothDeviceIsConnected(wiiremote->device); - return result; -} - -Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) -{ - post("wiiremote_search"); - IOReturn ret; - - if (wiiremote->inquiry != nil) - return true; - - wiiremote->inquiry = IOBluetoothDeviceInquiryCreateWithCallbackRefCon((void *)wiiremote); - IOBluetoothDeviceInquirySetDeviceFoundCallback(wiiremote->inquiry, myFoundFunc); - IOBluetoothDeviceInquirySetDeviceNameUpdatedCallback(wiiremote->inquiry, myUpdatedFunc); - IOBluetoothDeviceInquirySetCompleteCallback(wiiremote->inquiry, myCompleteFunc); - - if (wiiremote->address != nil) - CFRelease(wiiremote->address); - wiiremote->address = CFStringCreateWithCString(nil, address, kCFStringEncodingMacRoman); - - ret = IOBluetoothDeviceInquiryStart(wiiremote->inquiry); - if (ret != kIOReturnSuccess) - { - IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); - wiiremote->inquiry = nil; - return false; - } -#ifdef PD - CFRunLoopRun(); // PD doesn't use the Carbon loop, so we have to manually control it -#endif - return true; -} - -Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) -{ - post("wiiremote_stopsearch"); - IOReturn ret; - - if (wiiremote->inquiry == nil) - { - return true; // already stopped - } - - ret = IOBluetoothDeviceInquiryStop(wiiremote->inquiry); - - if (ret != kIOReturnSuccess && ret != kIOReturnNotPermitted) - { - // kIOReturnNotPermitted is if it's already stopped - } - - IOBluetoothDeviceInquiryDelete(wiiremote->inquiry); - wiiremote->inquiry = nil; - - return (ret==kIOReturnSuccess); -} - -//-------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------- - -unsigned char decrypt(unsigned char data) -{ - return (data ^ 0x17) + 0x17; -} - -//-------------------------------------------------------------------------------------------- - -/** -* Handle report 0x21 (Read Data) from wiimote. - * dp[0] = Bluetooth header - * dp[1] = (0x21) Report/Channel ID - * dp[2] = Wiimote Buttons - * dp[3] = Wiimote Buttons - * dp[4] = High 4 bits = payload size; Low 4 bits = Error flag (0 = all good) - * dp[5] = Offset of memory read - * dp[6] = Offset of memory read - * dp[7+] = the Data. - **/ - -void handleRAMData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) -{ - // specify attached expasion device - if ((dp[5] == 0x00) && (dp[6] == 0xF0)) - { - if (decrypt(dp[21]) == 0x00) - { - wiiremote->expType = WiiNunchuk; - } - else - if (decrypt(dp[21]) == 0x01) - { - wiiremote->expType = WiiClassicController; - } - else - { - wiiremote->expType = WiiExpNotAttached; - } - // initExpPort = NO; - return; - } - - // wiimote calibration data - if (!wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) - { - wiiremote->wiiCalibData.accX_zero = dp[7]; - wiiremote->wiiCalibData.accY_zero = dp[8]; - wiiremote->wiiCalibData.accZ_zero = dp[9]; - - //dp[10] - unknown/unused - - wiiremote->wiiCalibData.accX_1g = dp[11]; - wiiremote->wiiCalibData.accY_1g = dp[12]; - wiiremote->wiiCalibData.accZ_1g = dp[13]; - return; - } - - // expansion device calibration data. - if (wiiremote->readingRegister && dp[5] == 0x00 && dp[6] == 0x20) - { - if (wiiremote->expType == WiiNunchuk) - { - //nunchuk calibration data - wiiremote->nunchukCalibData.accX_zero = decrypt(dp[7]); - wiiremote->nunchukCalibData.accY_zero = decrypt(dp[8]); - wiiremote->nunchukCalibData.accZ_zero = decrypt(dp[9]); - - wiiremote->nunchukCalibData.accX_1g = decrypt(dp[11]); - wiiremote->nunchukCalibData.accY_1g = decrypt(dp[12]); - wiiremote->nunchukCalibData.accZ_1g = decrypt(dp[13]); - - wiiremote->nunchukJoyStickCalibData.x_max = decrypt(dp[15]); - wiiremote->nunchukJoyStickCalibData.x_min = decrypt(dp[16]); - wiiremote->nunchukJoyStickCalibData.x_center = decrypt(dp[17]); - - wiiremote->nunchukJoyStickCalibData.y_max = decrypt(dp[18]); - wiiremote->nunchukJoyStickCalibData.y_min = decrypt(dp[19]); - wiiremote->nunchukJoyStickCalibData.y_center = decrypt(dp[20]); - - return; - } - else - if (wiiremote->expType == WiiClassicController) - { - //classic controller calibration data (probably) - } - } - - // wii remote buttons - wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; -} - -void handleStatusReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) -{ - wiiremote->batteryLevel = (double)dp[7]; - wiiremote->batteryLevel /= (double)0xC0; // C0 = fully charged. - - if ((dp[4] & 0x02)) //some device attached to Wiimote - { - wiiremote->isExpansionPortAttached = true; - // initExpPort = YES; - - Boolean ret = writeData(wiiremote, (darr){0x00}, 0x04A40040, 1); // Initialize the device - - if (ret == false) - { - wiiremote->isExpansionPortAttached = false; - return; - } - - usleep(kWait); // Give the write a chance to be processed. - - ret = readData(wiiremote, 0x04A400F0, 16); // read expansion device type - if (ret == false) - { - wiiremote->isExpansionPortAttached = false; - } - } - else - { // unplugged - wiiremote->isExpansionPortAttached = false; - wiiremote->expType = WiiExpNotAttached; - } - - if (dp[4] & 0x10) - wiiremote->isLED1Illuminated = true; - else - wiiremote->isLED1Illuminated = false; - - if (dp[4] & 0x20) - wiiremote->isLED2Illuminated = true; - else - wiiremote->isLED2Illuminated = false; - - if (dp[4] & 0x40) - wiiremote->isLED3Illuminated = true; - else - wiiremote->isLED3Illuminated = false; - - if (dp[4] & 0x80) - wiiremote->isLED4Illuminated = true; - else - wiiremote->isLED4Illuminated = false; -} - -void handleExtensionData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) -{ - unsigned char startByte; - - switch (dp[1]) { - case 0x34 : - startByte = 4; - break; - case 0x35 : - startByte = 7; - break; - case 0x36 : - startByte = 14; - break; - case 0x37 : - startByte = 17; - break; - default: - return; // This shouldn't ever happen. - break; - } - - if (wiiremote->expType == WiiNunchuk) - { - wiiremote->nStickX = decrypt(dp[startByte]); - wiiremote->nStickY = decrypt(dp[startByte +1]); - wiiremote->nAccX = decrypt(dp[startByte +2]); - wiiremote->nAccY = decrypt(dp[startByte +3]); - wiiremote->nAccZ = decrypt(dp[startByte +4]); - wiiremote->nButtonData = decrypt(dp[startByte +5]); - - wiiremote->nLowZ = wiiremote->nLowZ * .9 + wiiremote->nAccZ * .1; - wiiremote->nLowX = wiiremote->nLowX * .9 + wiiremote->nAccX * .1; - - float absx = abs(wiiremote->nLowX - 128); - float absz = abs(wiiremote->nLowZ - 128); - - if (wiiremote->nOrientation == 0 || wiiremote->nOrientation == 2) absx -= 5; - if (wiiremote->nOrientation == 1 || wiiremote->nOrientation == 3) absz -= 5; - - if (absz >= absx) - { - if (absz > 5) - wiiremote->nOrientation = (wiiremote->nLowZ > 128) ? 0 : 2; - } - else - { - if (absx > 5) - wiiremote->nOrientation = (wiiremote->nLowX > 128) ? 3 : 1; - } - } - else - if (wiiremote->expType == WiiClassicController) - { - wiiremote->cButtonData = (unsigned short)(decrypt(dp[startByte + 4]) << 8) + decrypt(dp[startByte + 5]); - wiiremote->cButtonData = ~wiiremote->cButtonData; // bit reverse - - wiiremote->cStickX1 = decrypt(dp[startByte]) & 0x3F; - wiiremote->cStickY1 = decrypt(dp[startByte + 1]) & 0x3F; - - wiiremote->cStickX2 = (((decrypt(dp[startByte +0]) & 0xC0) >> 3) | - ((decrypt(dp[startByte +1]) & 0xC0) >> 5) | - ((decrypt(dp[startByte +2]) & 0x80) >> 7)) & 0x1F; - wiiremote->cStickY2 = decrypt(dp[startByte + 2]) & 0x1F; - - wiiremote->cAnalogL = (((decrypt(dp[startByte +2]) & 0x60) >> 2) | - ((decrypt(dp[startByte +3]) & 0xE0) >> 5)) & 0x1F; - wiiremote->cAnalogR = decrypt(dp[startByte + 3]) & 0x1F; - } -} - -void handleIRData(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) -{ - int i; - - if (dp[1] == 0x33) - { // 12 IR bytes - int startByte = 0; - for(i=0 ; i < 4 ; i++) - { - startByte = 7 + 3 * i; - wiiremote->irData[i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; - wiiremote->irData[i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; - wiiremote->irData[i].s = dp[startByte +2] & 0x0F; - } - } - else - { // 10 IR bytes - int shift = (dp[1] == 0x36) ? 4 : 7; - int startByte = 0; - for (i=0; i < 2; i++) { - startByte = shift + 5 * i; - wiiremote->irData[2*i].x = (dp[startByte +0] | ((dp[startByte +2] & 0x30) << 4)) & 0x3FF; - wiiremote->irData[2*i].y = (dp[startByte +1] | ((dp[startByte +2] & 0xC0) << 2)) & 0x3FF; - wiiremote->irData[2*i].s = ((wiiremote->irData[2*i].x == wiiremote->irData[2*i].y) && (wiiremote->irData[2*i].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. - - wiiremote->irData[(2*i)+1].x = (dp[startByte +3] | ((dp[startByte +2] & 0x03) << 8)) & 0x3FF; - wiiremote->irData[(2*i)+1].y = (dp[startByte +4] | ((dp[startByte +2] & 0x0C) << 6)) & 0x3FF; - wiiremote->irData[(2*i)+1].s = ((wiiremote->irData[(2*i)+1].x == wiiremote->irData[(2*i)+1].y) && (wiiremote->irData[(2*i)+1].x == 0x3FF)) ? 0x0F : 0x05; // No size is given in 10 byte report. - } - } - - int p1 = -1; - int p2 = -1; - // we should modify this loop to take the points with the lowest s (the brightest ones) - for (i=0 ; i<4 ; i++) { - if (p1 == -1) { - if (wiiremote->irData [i].s < 0x0F) - p1 = i; - } else { - if (wiiremote->irData [i].s < 0x0F) { - p2 = i; - break; - } - } - } - - double ox, oy; - if ((p1 > -1) && (p2 > -1)) - { - int l = wiiremote->leftPoint; - if (wiiremote->leftPoint == -1) - { - switch (wiiremote->orientation) - { - case 0: l = (wiiremote->irData[p1].x < wiiremote->irData[p2].x) ? 0 : 1; break; - case 1: l = (wiiremote->irData[p1].y > wiiremote->irData[p2].y) ? 0 : 1; break; - case 2: l = (wiiremote->irData[p1].x > wiiremote->irData[p2].x) ? 0 : 1; break; - case 3: l = (wiiremote->irData[p1].y < wiiremote->irData[p2].y) ? 0 : 1; break; - } - - wiiremote->leftPoint = l; - } - - int r = 1-l; - - double dx = wiiremote->irData[r].x - wiiremote->irData[l].x; - double dy = wiiremote->irData[r].y - wiiremote->irData[l].y; - double d = hypot (dx, dy); - - dx /= d; - dy /= d; - - double cx = (wiiremote->irData[l].x + wiiremote->irData[r].x)/kWiiIRPixelsWidth - 1; - double cy = (wiiremote->irData[l].y + wiiremote->irData[r].y)/kWiiIRPixelsHeight - 1; - - ox = -dy*cy-dx*cx; - oy = -dx*cy+dy*cx; - - // cam: - // Compensate for distance. There must be fewer than 0.75*768 pixels between the spots for this to work. - // In other words, you have to be far enough away from the sensor bar for the two spots to have enough - // space on the image sensor to travel without one of the points going off the image. - // note: it is working very well ... - double gain = 4; - if (d < (0.75 * kWiiIRPixelsHeight)) - gain = 1 / (1 - d/kWiiIRPixelsHeight); - - ox *= gain; - oy *= gain; - - wiiremote->angle = atan2(dy, dx); - wiiremote->tracking = true; - } - else - { - ox = oy = -100; - wiiremote->leftPoint = -1; // not tracking - wiiremote->angle = -100; - wiiremote->tracking = false; - } - - wiiremote->posX = ox; - wiiremote->posY = oy; -} - -void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLength) -{ - // wiimote buttons - wiiremote->buttonData = ((short)dp[2] << 8) + dp[3]; - - // report contains extension data - switch (dp[1]) - { - case 0x34 : - case 0x35 : - case 0x36 : - case 0x37 : - handleExtensionData(wiiremote, dp, dataLength); - break; - } - - // report contains IR data - if (dp[1] & 0x02) - { - handleIRData(wiiremote, dp, dataLength); - } - - // report contains motion sensor data - if (dp[1] & 0x01) - { - wiiremote->accX = dp[4]; - wiiremote->accY = dp[5]; - wiiremote->accZ = dp[6]; - - wiiremote->lowZ = wiiremote->lowZ * 0.9 + wiiremote->accZ * 0.1; - wiiremote->lowX = wiiremote->lowX * 0.9 + wiiremote->accX * 0.1; - - float absx = abs(wiiremote->lowX-128); - float absz = abs(wiiremote->lowZ-128); - - if (wiiremote->orientation == 0 || wiiremote->orientation == 2) absx -= 5; - if (wiiremote->orientation == 1 || wiiremote->orientation == 3) absz -= 5; - - if (absz >= absx) - { - if (absz > 5) - wiiremote->orientation = (wiiremote->lowZ > 128)?0:2; - } - else - { - if (absx > 5) - wiiremote->orientation = (wiiremote->lowX > 128)?3:1; - } - } -} - -//-------------------------------------------------------------------------------------------- - - void myDataListener(IOBluetoothL2CAPChannelRef channel, void *dataPointer, UInt16 dataLength, void *refCon) -{ - WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; - unsigned char* dp = (unsigned char*)dataPointer; - - if (!wiiremote->device) - return; - - //controller status (expansion port and battery level data) - received when report 0x15 sent to Wiimote (getCurrentStatus:) or status of expansion port changes. - if (dp[1] == 0x20 && dataLength >= 8) - { - handleStatusReport(wiiremote, dp, dataLength); - requestUpdates(wiiremote); // Make sure we keep getting state change reports. - return; - } - - if (dp[1] == 0x21) - { - handleRAMData(wiiremote, dp, dataLength); - return; - } - - if (dp[1] == 0x22) - { // Write data response - //NSLog(@"Write data response: %00x %00x %00x %00x", dp[2], dp[3], dp[4], dp[5]); - return; - } - - // report contains button info - if ((dp[1] & 0xF0) == 0x30) - { - handleButtonReport(wiiremote, dp, dataLength); - } -} - -void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) -{ - if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) - { - // In thise case: - // event->u.newData.dataPtr is a pointer to the block of data received. - // event->u.newData.dataSize is the size of the block of data. - myDataListener(channel, event->u.data.dataPtr, event->u.data.dataSize, refCon); - } - else - if (event->eventType == kIOBluetoothL2CAPChannelEventTypeClosed) - { - // In this case: - // event->u.terminatedChannel is the channel that was terminated. It can be converted in an IOBluetoothL2CAPChannel - // object with [IOBluetoothL2CAPChannel withL2CAPChannelRef:]. (see below). - } -} - -void myDisconnectedFunc(void * refCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef) -{ - CFStringRef itsAddress, myAddress; - - itsAddress = IOBluetoothDeviceGetAddressString(objectRef); - if (itsAddress != nil) - { - myAddress = IOBluetoothDeviceGetAddressString(((WiiRemoteRef)refCon)->device); - if (myAddress != nil) - { - if (CFStringCompare(itsAddress, myAddress, 0) == kCFCompareEqualTo) - { - wiiremote_disconnect((WiiRemoteRef)refCon); - } - CFRelease(myAddress); - } - CFRelease(itsAddress); - } -} - -//-------------------------------------------------------------------------------------------- - -void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address) -{ - CFStringRef cfstring; - - cfstring = IOBluetoothDeviceGetAddressString(wiiremote->device); - CFStringGetCString(cfstring, address, 32, kCFStringEncodingMacRoman); - CFRelease(cfstring); - -} - -//-------------------------------------------------------------------------------------------- - -Boolean wiiremote_connect(WiiRemoteRef wiiremote) -{ - IOReturn ret; - Boolean result; - short i; - - if (wiiremote->device == nil) - return false; - - // connect the device - for (i=0; idevice, nil, nil); - if ( ret == kIOReturnSuccess) - break; - usleep(kWait); // wait 10ms - } - if (i==kTrial) - return false; - - wiiremote->disconnectNotification = IOBluetoothDeviceRegisterForDisconnectNotification(wiiremote->device, myDisconnectedFunc, (void *)wiiremote); - - // performs an SDP query - for (i=0; idevice, nil, nil); - if ( ret == kIOReturnSuccess) - break; - usleep(kWait); // wait 10ms - } - if (i==kTrial) - return false; - - result = openCChan(wiiremote); - result = openIChan(wiiremote); - - if (result) - { - result = wiiremote_led(wiiremote, wiiremote->isLED1Illuminated, wiiremote->isLED2Illuminated, wiiremote->isLED3Illuminated, wiiremote->isLED4Illuminated); - } - - if (result == false) - { - wiiremote_disconnect(wiiremote); - return result; - } - - wiiremote_getstatus(wiiremote); - requestUpdates(wiiremote); - - readData(wiiremote, 0x0020, 7); // Get Accelerometer callibration data - - return true; -} - - -Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) -{ - short i = 0; - - if (wiiremote->cchan) - { - if (IOBluetoothDeviceIsConnected(wiiremote->device)) - { - for (i=0; icchan) == kIOReturnSuccess) - break; - usleep(kWait); // wait 10ms - } - } - if (i==kTrial) return false; - IOBluetoothObjectRelease(wiiremote->cchan); - wiiremote->cchan = nil; - } - - if (wiiremote->ichan) - { - if (IOBluetoothDeviceIsConnected(wiiremote->device)) - { - for (i=0; iichan) == kIOReturnSuccess) - break; - } - } - if (i==kTrial) return false; - IOBluetoothObjectRelease(wiiremote->ichan); - wiiremote->ichan = nil; - } - - if (wiiremote->device) - { - if (IOBluetoothDeviceIsConnected(wiiremote->device)) - { - for (i=0; idevice) == kIOReturnSuccess) - break; - } - } - if (i==kTrial) return false; - IOBluetoothObjectRelease(wiiremote->device); - wiiremote->device = nil; - } - - if (wiiremote->disconnectNotification != nil) - { - IOBluetoothUserNotificationUnregister(wiiremote->disconnectNotification); - wiiremote->disconnectNotification = nil; - } - - return true; -} - -//-------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------- - -Boolean requestUpdates(WiiRemoteRef wiiremote) -{ - Boolean result; - - // Set the report type the Wiimote should send. - unsigned char cmd[] = {0x12, 0x02, 0x30}; // Just buttons. - - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - - /* - There are numerous status report types that can be requested. - The IR reports must be matched with the data format set when initializing the IR camera: - 0x36, 0x37 - 10 IR bytes go with Basic mode - 0x33 - 12 IR bytes go with Extended mode - 0x3e/0x3f - 36 IR bytes go with Full mode - - The Nunchuk and Classic controller use 6 bytes to report their state, so the reports that - give more extension bytes don't provide any more info. - - Buttons | Accelerometer | IR | Extension - --------------------+-------------------+-----------+------------- - 0x30: Core Buttons | | | - 0x31: Core Buttons | Accelerometer | | - 0x32: Core Buttons | | | 8 bytes - 0x33: Core Buttons | Accelerometer | 12 bytes | - 0x34: Core Buttons | | | 19 bytes - 0x35: Core Buttons | Accelerometer | | 16 bytes - 0x36: Core Buttons | | 10 bytes | 9 bytes - 0x37: Core Buttons | Accelerometer | 10 bytes | 6 bytes - ?? 0x38: Core Buttons and Accelerometer with 16 IR bytes ?? - 0x3d: | | | 21 bytes - - 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 16/36 IR bytes - - */ - - if (wiiremote->isIRSensorEnabled) - { - if (wiiremote->isExpansionPortEnabled) - { - cmd[2] = 0x36; // Buttons, 10 IR Bytes, 9 Extension Bytes - wiiremote->wiiIRMode = kWiiIRModeBasic; - } - else - { - cmd[2] = 0x33; // Buttons, Accelerometer, and 12 IR Bytes. - wiiremote->wiiIRMode = kWiiIRModeExtended; - } - - // Set IR Mode - writeData(wiiremote, (darr){ wiiremote->wiiIRMode }, 0x04B00033, 1); - usleep(kWait); // wait 10ms - } - else - { - if (wiiremote->isExpansionPortEnabled) - { - cmd[2] = 0x34; // Buttons, 19 Extension Bytes - } - else - { - cmd[2] = 0x30; // Buttons - } - } - - if (wiiremote->isMotionSensorEnabled) cmd[2] |= 0x01; // Add Accelerometer - - usleep(kWait); // wait 10ms - result = sendCommand(wiiremote, cmd, 3); - - return(result); -} - -//-------------------------------------------------------------------------------------------- - -Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled) -{ - wiiremote->isMotionSensorEnabled = enabled; - return requestUpdates(wiiremote); -} - -Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled) -{ - - wiiremote->isVibrationEnabled = enabled; - return requestUpdates(wiiremote); -} - -Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4) -{ - unsigned char cmd[] = {0x11, 0x00}; - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (enabled1) cmd[1] |= 0x10; - if (enabled2) cmd[1] |= 0x20; - if (enabled3) cmd[1] |= 0x40; - if (enabled4) cmd[1] |= 0x80; - - wiiremote->isLED1Illuminated = enabled1; - wiiremote->isLED2Illuminated = enabled2; - wiiremote->isLED3Illuminated = enabled3; - wiiremote->isLED4Illuminated = enabled4; - - return sendCommand(wiiremote, cmd, 2); -} - -Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled) -{ - wiiremote->isExpansionPortEnabled = enabled; - if (wiiremote->isExpansionPortAttached == false) - { - wiiremote->isExpansionPortEnabled = false; - } - else - { - readData(wiiremote, 0x04A40020, 16); //get calbdata - } - - return requestUpdates(wiiremote); -} - -Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled) -{ - Boolean ret; - - wiiremote->isIRSensorEnabled = enabled; - - // ir enable 1 - unsigned char cmd[] = {0x13, 0x00}; - if (wiiremote->isVibrationEnabled) cmd[1] |= 0x01; - if (wiiremote->isIRSensorEnabled) cmd[1] |= 0x04; - if ((ret = sendCommand(wiiremote, cmd, 2)) == false) - return ret; - usleep(kWait); - - // set register 0x1a (ir enable 2) - unsigned char cmd2[] = {0x1a, 0x00}; - if (enabled) cmd2[1] |= 0x04; - if ((ret = sendCommand(wiiremote, cmd2, 2)) == false) - return ret; - usleep(kWait); - - if(enabled) - { - // based on marcan's method, found on wiili wiki: - // tweaked to include some aspects of cliff's setup procedure in the hopes - // of it actually turning on 100% of the time (was seeing 30-40% failure rate before) - // the sleeps help it it seems - usleep(kWait); - if ((ret = writeData(wiiremote, (darr){0x01}, 0x04B00030, 1)) == false) return ret; - usleep(kWait); - if ((ret = writeData(wiiremote, (darr){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xC0}, 0x04B00000, 9)) == false) return ret; - usleep(kWait); - if ((ret = writeData(wiiremote, (darr){0x40, 0x00}, 0x04B0001A, 2)) == false) return ret; - usleep(kWait); - if ((ret = writeData(wiiremote, (darr){0x08}, 0x04B00030, 1)) == false) return ret; - usleep(kWait); - - requestUpdates(wiiremote); - } - else - { - // probably should do some writes to power down the camera, save battery - // but don't know how yet. - - ret = wiiremote_motionsensor(wiiremote, wiiremote->isMotionSensorEnabled); - ret = wiiremote_vibration(wiiremote, wiiremote->isVibrationEnabled); - ret = wiiremote_expansion(wiiremote, wiiremote->isExpansionPortEnabled); - } - - return ret; -} - -Boolean wiiremote_getstatus(WiiRemoteRef wiiremote) -{ - unsigned char cmd[] = {0x15, 0x00}; - return sendCommand(wiiremote, cmd, 2); -} - - diff --git a/wiiremote/wiiremote.h b/wiiremote/wiiremote.h deleted file mode 100644 index 4a03f09..0000000 --- a/wiiremote/wiiremote.h +++ /dev/null @@ -1,175 +0,0 @@ -// wiiremote.h -// Copyright by Masayuki Akamatsu -// Based on "DarwiinRemote" by Hiroaki Kimura - -#include -#include -#include -#include -#include - -// Macros for PD for compability with Max macros -#ifdef PD -#define SETSYM SETSYMBOL -#define SETLONG SETFLOAT -#endif - -typedef unsigned char WiiIRModeType; -enum { - kWiiIRModeBasic = 0x01, - kWiiIRModeExtended = 0x03, - kWiiIRModeFull = 0x05 -}; - -typedef struct { - int x, y, s; -} IRData; - -typedef struct { - unsigned char accX_zero, accY_zero, accZ_zero, accX_1g, accY_1g, accZ_1g; -} WiiAccCalibData; - -typedef struct { - unsigned char x_min, x_max, x_center, y_min, y_max, y_center; -} WiiJoyStickCalibData; - -typedef UInt16 WiiButtonType; -enum { - WiiRemoteAButton, - WiiRemoteBButton, - WiiRemoteOneButton, - WiiRemoteTwoButton, - WiiRemoteMinusButton, - WiiRemoteHomeButton, - WiiRemotePlusButton, - WiiRemoteUpButton, - WiiRemoteDownButton, - WiiRemoteLeftButton, - WiiRemoteRightButton, - - WiiNunchukZButton, - WiiNunchukCButton, - - WiiClassicControllerXButton, - WiiClassicControllerYButton, - WiiClassicControllerAButton, - WiiClassicControllerBButton, - WiiClassicControllerLButton, - WiiClassicControllerRButton, - WiiClassicControllerZLButton, - WiiClassicControllerZRButton, - WiiClassicControllerUpButton, - WiiClassicControllerDownButton, - WiiClassicControllerLeftButton, - WiiClassicControllerRightButton, - WiiClassicControllerMinusButton, - WiiClassicControllerHomeButton, - WiiClassicControllerPlusButton -}; - -typedef UInt16 WiiExpansionPortType; -enum{ - WiiExpNotAttached, - WiiNunchuk, - WiiClassicController -}; - -typedef UInt16 WiiAccelerationSensorType; -enum{ - WiiRemoteAccelerationSensor, - WiiNunchukAccelerationSensor -}; - - -typedef UInt16 WiiJoyStickType; -enum{ - WiiNunchukJoyStick, - WiiClassicControllerLeftJoyStick, - WiiClassicControllerRightJoyStick -}; - - -typedef struct _WiiRemoteRec -{ - IOBluetoothDeviceInquiryRef inquiry; - IOBluetoothDeviceRef device; - IOBluetoothL2CAPChannelRef ichan; - IOBluetoothL2CAPChannelRef cchan; - - CFStringRef address; - - unsigned char accX; - unsigned char accY; - unsigned char accZ; - unsigned short buttonData; - - float lowZ; - float lowX; - int orientation; - int leftPoint; // is point 0 or 1 on the left. -1 when not tracking. - - float posX; - float posY; - float angle; - Boolean tracking; - - WiiExpansionPortType expType; - WiiAccCalibData wiiCalibData, nunchukCalibData; - WiiJoyStickCalibData nunchukJoyStickCalibData; - WiiIRModeType wiiIRMode; - IRData irData[4]; - double batteryLevel; - - Boolean readingRegister; - Boolean isMotionSensorEnabled; - Boolean isIRSensorEnabled; - Boolean isVibrationEnabled; - Boolean isExpansionPortEnabled; - Boolean initExpPort; - Boolean isLED1Illuminated; - Boolean isLED2Illuminated; - Boolean isLED3Illuminated; - Boolean isLED4Illuminated; - Boolean isExtraOutputEnabled; - - Boolean isExpansionPortAttached; - - IOBluetoothUserNotificationRef disconnectNotification; - - //nunchuk - unsigned char nStickX; - unsigned char nStickY; - unsigned char nAccX; - unsigned char nAccY; - unsigned char nAccZ; - unsigned char nButtonData; - - float nLowZ; - float nLowX; - int nOrientation; - - //classic controller - unsigned short cButtonData; - unsigned char cStickX1; - unsigned char cStickY1; - unsigned char cStickX2; - unsigned char cStickY2; - unsigned char cAnalogL; - unsigned char cAnalogR; - -} WiiRemoteRec, *WiiRemoteRef; - -void wiiremote_init(WiiRemoteRef wiiremote); -Boolean wiiremote_isconnected(WiiRemoteRef wiiremote); -Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address); -Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote); -Boolean wiiremote_connect(WiiRemoteRef wiiremote); -Boolean wiiremote_disconnect(WiiRemoteRef wiiremote); -void wiiremote_getaddress(WiiRemoteRef wiiremote, char *address); -Boolean wiiremote_motionsensor(WiiRemoteRef wiiremote, Boolean enabled); -Boolean wiiremote_irsensor(WiiRemoteRef wiiremote, Boolean enabled); -Boolean wiiremote_vibration(WiiRemoteRef wiiremote, Boolean enabled); -Boolean wiiremote_led(WiiRemoteRef wiiremote, Boolean enabled1, Boolean enabled2, Boolean enabled3, Boolean enabled4); -Boolean wiiremote_expansion(WiiRemoteRef wiiremote, Boolean enabled); -Boolean wiiremote_getstatus(WiiRemoteRef wiiremote); - -- cgit v1.2.1 From b68834346483649aee638c4cf749d124097d6361 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 10 Mar 2008 21:51:41 +0000 Subject: moved wiiremote to aka.wiiremote to reflect the name of the Max/MSP object. This is a direct port, so it makes sense to have the same name. svn path=/trunk/externals/io/; revision=9552 --- aka.wiiremote/aka.wiiremote-help.pd | 80 +++++++++++++++++++++++++++++++++++++ aka.wiiremote/wiiremote-help.pd | 80 ------------------------------------- 2 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 aka.wiiremote/aka.wiiremote-help.pd delete mode 100644 aka.wiiremote/wiiremote-help.pd diff --git a/aka.wiiremote/aka.wiiremote-help.pd b/aka.wiiremote/aka.wiiremote-help.pd new file mode 100644 index 0000000..5c8f610 --- /dev/null +++ b/aka.wiiremote/aka.wiiremote-help.pd @@ -0,0 +1,80 @@ +#N canvas 287 96 744 626 10; +#X msg 128 207 connect; +#X msg 141 228 disconnect; +#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 127 285 metro 100; +#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 89 283 bang; +#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote +with your computer (only required for the first use).; +#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs +will start blinking.; +#X text 49 109 - Click on the [connect( message \, the LEDs will stop +blinking once its connected; +#X text 49 139 - Start the [metro] to get updates from [wiiremote] +; +#X obj 399 526 pddp/print; +#X obj 354 556 pddp/print; +#X obj 354 410 route remote; +#X msg 503 290 getbattery; +#X msg 503 310 getled; +#X msg 503 330 getexpansion; +#X obj 489 431 print RIGHT; +#X obj 253 430 print LEFT; +#X obj 354 476 route motion buttons ir; +#X obj 444 497 pddp/print; +#X msg 294 224 ir \$1; +#X msg 218 225 motion \$1; +#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 344 224 vibration \$1; +#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 434 224 expansion \$1; +#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 524 223 extraoutput \$1; +#N canvas 254 342 450 300 address 0; +#X obj 176 252 outlet; +#X msg 206 126 getaddress; +#X msg 176 72 address 00-1e-35-4c-e6-f1; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X restore 25 462 pd address; +#X msg 503 352 getaddress; +#X obj 631 536 dac~; +#X obj 632 408 pddp/dsp; +#X obj 640 500 osc~ 100; +#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1; +#X connect 0 0 34 0; +#X connect 1 0 34 0; +#X connect 2 0 22 0; +#X connect 3 0 21 0; +#X connect 4 0 34 0; +#X connect 5 0 4 0; +#X connect 6 0 34 0; +#X connect 13 0 19 0; +#X connect 13 1 17 0; +#X connect 14 0 34 0; +#X connect 15 0 34 0; +#X connect 16 0 34 0; +#X connect 19 0 12 0; +#X connect 19 1 11 0; +#X connect 19 2 20 0; +#X connect 21 0 34 0; +#X connect 22 0 34 0; +#X connect 23 0 24 0; +#X connect 24 0 34 0; +#X connect 25 0 26 0; +#X connect 26 0 34 0; +#X connect 27 0 28 0; +#X connect 28 0 34 0; +#X connect 30 0 34 0; +#X connect 33 0 31 0; +#X connect 33 0 31 1; +#X connect 34 0 18 0; +#X connect 34 1 13 0; diff --git a/aka.wiiremote/wiiremote-help.pd b/aka.wiiremote/wiiremote-help.pd deleted file mode 100644 index 5c8f610..0000000 --- a/aka.wiiremote/wiiremote-help.pd +++ /dev/null @@ -1,80 +0,0 @@ -#N canvas 287 96 744 626 10; -#X msg 128 207 connect; -#X msg 141 228 disconnect; -#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 127 285 metro 100; -#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 89 283 bang; -#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote -with your computer (only required for the first use).; -#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs -will start blinking.; -#X text 49 109 - Click on the [connect( message \, the LEDs will stop -blinking once its connected; -#X text 49 139 - Start the [metro] to get updates from [wiiremote] -; -#X obj 399 526 pddp/print; -#X obj 354 556 pddp/print; -#X obj 354 410 route remote; -#X msg 503 290 getbattery; -#X msg 503 310 getled; -#X msg 503 330 getexpansion; -#X obj 489 431 print RIGHT; -#X obj 253 430 print LEFT; -#X obj 354 476 route motion buttons ir; -#X obj 444 497 pddp/print; -#X msg 294 224 ir \$1; -#X msg 218 225 motion \$1; -#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 344 224 vibration \$1; -#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 434 224 expansion \$1; -#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 524 223 extraoutput \$1; -#N canvas 254 342 450 300 address 0; -#X obj 176 252 outlet; -#X msg 206 126 getaddress; -#X msg 176 72 address 00-1e-35-4c-e6-f1; -#X connect 1 0 0 0; -#X connect 2 0 0 0; -#X restore 25 462 pd address; -#X msg 503 352 getaddress; -#X obj 631 536 dac~; -#X obj 632 408 pddp/dsp; -#X obj 640 500 osc~ 100; -#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1; -#X connect 0 0 34 0; -#X connect 1 0 34 0; -#X connect 2 0 22 0; -#X connect 3 0 21 0; -#X connect 4 0 34 0; -#X connect 5 0 4 0; -#X connect 6 0 34 0; -#X connect 13 0 19 0; -#X connect 13 1 17 0; -#X connect 14 0 34 0; -#X connect 15 0 34 0; -#X connect 16 0 34 0; -#X connect 19 0 12 0; -#X connect 19 1 11 0; -#X connect 19 2 20 0; -#X connect 21 0 34 0; -#X connect 22 0 34 0; -#X connect 23 0 24 0; -#X connect 24 0 34 0; -#X connect 25 0 26 0; -#X connect 26 0 34 0; -#X connect 27 0 28 0; -#X connect 28 0 34 0; -#X connect 30 0 34 0; -#X connect 33 0 31 0; -#X connect 33 0 31 1; -#X connect 34 0 18 0; -#X connect 34 1 13 0; -- cgit v1.2.1 From eb95f74725288feef6a214fe754a966bcbf7311e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 10 Mar 2008 21:52:30 +0000 Subject: changed object names to reflect name change svn path=/trunk/externals/io/; revision=9553 --- aka.wiiremote/aka.wiiremote-help.pd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aka.wiiremote/aka.wiiremote-help.pd b/aka.wiiremote/aka.wiiremote-help.pd index 5c8f610..4c32d94 100644 --- a/aka.wiiremote/aka.wiiremote-help.pd +++ b/aka.wiiremote/aka.wiiremote-help.pd @@ -15,7 +15,7 @@ with your computer (only required for the first use).; will start blinking.; #X text 49 109 - Click on the [connect( message \, the LEDs will stop blinking once its connected; -#X text 49 139 - Start the [metro] to get updates from [wiiremote] +#X text 49 139 - Start the [metro] to get updates from [aka.wiiremote] ; #X obj 399 526 pddp/print; #X obj 354 556 pddp/print; @@ -49,7 +49,7 @@ blinking once its connected; #X obj 631 536 dac~; #X obj 632 408 pddp/dsp; #X obj 640 500 osc~ 100; -#X obj 303 388 wiiremote 00-1e-35-4c-e6-f1; +#X obj 303 388 aka.wiiremote 00-1e-35-4c-e6-f1; #X connect 0 0 34 0; #X connect 1 0 34 0; #X connect 2 0 22 0; -- cgit v1.2.1 From 430e10e0813bc4a39f155640fdf70a76a03fb191 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 27 May 2008 19:10:02 +0000 Subject: first attempt at adding a CFRunLoop in order to get the events svn path=/trunk/externals/io/; revision=9929 --- aka.wiiremote/aka.wiiremote-help.pd | 33 +++++++++--------- aka.wiiremote/aka.wiiremote.c | 69 +++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 38 deletions(-) diff --git a/aka.wiiremote/aka.wiiremote-help.pd b/aka.wiiremote/aka.wiiremote-help.pd index 4c32d94..83def15 100644 --- a/aka.wiiremote/aka.wiiremote-help.pd +++ b/aka.wiiremote/aka.wiiremote-help.pd @@ -49,32 +49,33 @@ blinking once its connected; #X obj 631 536 dac~; #X obj 632 408 pddp/dsp; #X obj 640 500 osc~ 100; -#X obj 303 388 aka.wiiremote 00-1e-35-4c-e6-f1; -#X connect 0 0 34 0; -#X connect 1 0 34 0; +#X obj 154 513 aka.wiiremote; +#X obj 303 388 aka.wiiremote; +#X connect 0 0 35 0; +#X connect 1 0 35 0; #X connect 2 0 22 0; #X connect 3 0 21 0; -#X connect 4 0 34 0; +#X connect 4 0 35 0; #X connect 5 0 4 0; -#X connect 6 0 34 0; +#X connect 6 0 35 0; #X connect 13 0 19 0; #X connect 13 1 17 0; -#X connect 14 0 34 0; -#X connect 15 0 34 0; -#X connect 16 0 34 0; +#X connect 14 0 35 0; +#X connect 15 0 35 0; +#X connect 16 0 35 0; #X connect 19 0 12 0; #X connect 19 1 11 0; #X connect 19 2 20 0; -#X connect 21 0 34 0; -#X connect 22 0 34 0; +#X connect 21 0 35 0; +#X connect 22 0 35 0; #X connect 23 0 24 0; -#X connect 24 0 34 0; +#X connect 24 0 35 0; #X connect 25 0 26 0; -#X connect 26 0 34 0; +#X connect 26 0 35 0; #X connect 27 0 28 0; -#X connect 28 0 34 0; -#X connect 30 0 34 0; +#X connect 28 0 35 0; +#X connect 30 0 35 0; #X connect 33 0 31 0; #X connect 33 0 31 1; -#X connect 34 0 18 0; -#X connect 34 1 13 0; +#X connect 35 0 18 0; +#X connect 35 1 13 0; diff --git a/aka.wiiremote/aka.wiiremote.c b/aka.wiiremote/aka.wiiremote.c index 767d737..d8b12cb 100644 --- a/aka.wiiremote/aka.wiiremote.c +++ b/aka.wiiremote/aka.wiiremote.c @@ -15,9 +15,12 @@ #define method t_method //#define addbang(x) class_addbang(wiiremote_class, (x)) //#define addmess(x) class_addmessage(class_wiiremote, (x)) -static t_class *wiiremote_class; +// a CFRunLoop is needed for Pd since the 'pd' process is not a Carbon app +static t_class *akawiiremote_class; #else /* Max */ #include "ext.h" + +void *akawiiremote_class; // the number of instance of this object #endif /* PD */ #include "wiiremote.h" @@ -45,7 +48,11 @@ typedef struct _akawiiremote void *dataOut; } t_akawiiremote; -void *akawiiremote_class; // the number of instance of this object +#ifdef PD +static IONotificationPortRef gNotifyPort; +static io_iterator_t gAddedIter; +static CFRunLoopRef gRunLoop; +#endif void akawiiremote_bang(t_akawiiremote *x); void akawiiremote_address(t_akawiiremote *x, t_symbol *s); @@ -74,7 +81,7 @@ char nunchukStr[] = "nunchuk"; char classicStr[] = "classic"; #ifdef PD -void wiiremote_setup() +void setup_aka0x2ewiiremote() #else /* Max */ void main() #endif /* PD */ @@ -101,30 +108,30 @@ void main() #ifdef PD post("\tPd port by Hans-Christoph Steiner"); - wiiremote_class = class_new(gensym("wiiremote"), + akawiiremote_class = class_new(gensym("aka.wiiremote"), (t_newmethod)akawiiremote_new, (t_method)akawiiremote_free, sizeof(t_akawiiremote), CLASS_DEFAULT, A_GIMME,0); - class_addbang(wiiremote_class,(t_method)akawiiremote_bang); - class_addmethod(wiiremote_class,(t_method)akawiiremote_address,gensym("address"),A_DEFSYMBOL, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("expansion"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_expansion,gensym("nunchuk"), A_DEFFLOAT, 0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_extraoutput,gensym("extraoutput"), A_DEFFLOAT, 0); // B7 - - class_addmethod(wiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getaddress,gensym("getaddress"),0); - class_addmethod(wiiremote_class,(t_method)akawiiremote_getcalibration,gensym("getcalibration"), 0); + class_addbang(akawiiremote_class,(t_method)akawiiremote_bang); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_address,gensym("address"),A_DEFSYMBOL, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_connect,gensym("connect"),0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_disconnect,gensym("disconnect"),0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_motionsensor,gensym("motion"), A_DEFFLOAT, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_irsensor,gensym("ir"), A_DEFFLOAT, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_vibration,gensym("vibration"), A_DEFFLOAT, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_led,gensym("led"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_expansion,gensym("expansion"), A_DEFFLOAT, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_expansion,gensym("nunchuk"), A_DEFFLOAT, 0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_extraoutput,gensym("extraoutput"), A_DEFFLOAT, 0); // B7 + + class_addmethod(akawiiremote_class,(t_method)akawiiremote_getbattery,gensym("getbattery"),0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_getexpansion,gensym("getexpansion"),0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_getled,gensym("getled"),0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_getaddress,gensym("getaddress"),0); + class_addmethod(akawiiremote_class,(t_method)akawiiremote_getcalibration,gensym("getcalibration"), 0); #else /* Max */ setup((t_messlist **)&akawiiremote_class, (method)akawiiremote_new, (method)akawiiremote_free, (short)sizeof(t_akawiiremote), 0L, A_GIMME, 0); @@ -578,7 +585,7 @@ void akawiiremote_assist(t_akawiiremote *x, void *b, long m, long a, char *s) void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) { #ifdef PD - t_akawiiremote *x = (t_akawiiremote *)pd_new(wiiremote_class); + t_akawiiremote *x = (t_akawiiremote *)pd_new(akawiiremote_class); t_symbol *first_argument; x->statusOut = outlet_new(&x->x_obj, 0); @@ -588,6 +595,24 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) first_argument = atom_getsymbolarg(0, ac, av); if(first_argument != &s_) atom_string(av, x->address, MAXPDSTRING-1); + + IOReturn result = kIOReturnSuccess; + mach_port_t masterPort = NULL; + result = IOMasterPort (bootstrap_port, &masterPort); + if (kIOReturnSuccess != result) + pd_error("IOMasterPort error with bootstrap_port, error %d", result); + else + { + // Create a notification port and add its run loop event source to our run loop + // This is how async notifications get set up. + CFRunLoopSourceRef runLoopSource; + + gNotifyPort = IONotificationPortCreate(masterPort); + runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort); + + gRunLoop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode); + } #else /* Max */ t_akawiiremote *x; -- cgit v1.2.1 From dc185c66b8b0648fe068fdbeaedabc0e24cb4e4b Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 28 May 2008 10:49:34 +0000 Subject: changed classname to akawiiremote so that I don't have to deal with the hexloader svn path=/trunk/externals/io/; revision=9931 --- aka.wiiremote/aka.wiiremote-help.pd | 33 ++++++++++++++++----------------- aka.wiiremote/aka.wiiremote.c | 8 ++++---- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/aka.wiiremote/aka.wiiremote-help.pd b/aka.wiiremote/aka.wiiremote-help.pd index 83def15..c3ae89a 100644 --- a/aka.wiiremote/aka.wiiremote-help.pd +++ b/aka.wiiremote/aka.wiiremote-help.pd @@ -49,33 +49,32 @@ blinking once its connected; #X obj 631 536 dac~; #X obj 632 408 pddp/dsp; #X obj 640 500 osc~ 100; -#X obj 154 513 aka.wiiremote; -#X obj 303 388 aka.wiiremote; -#X connect 0 0 35 0; -#X connect 1 0 35 0; +#X obj 303 388 akawiiremote; +#X connect 0 0 34 0; +#X connect 1 0 34 0; #X connect 2 0 22 0; #X connect 3 0 21 0; -#X connect 4 0 35 0; +#X connect 4 0 34 0; #X connect 5 0 4 0; -#X connect 6 0 35 0; +#X connect 6 0 34 0; #X connect 13 0 19 0; #X connect 13 1 17 0; -#X connect 14 0 35 0; -#X connect 15 0 35 0; -#X connect 16 0 35 0; +#X connect 14 0 34 0; +#X connect 15 0 34 0; +#X connect 16 0 34 0; #X connect 19 0 12 0; #X connect 19 1 11 0; #X connect 19 2 20 0; -#X connect 21 0 35 0; -#X connect 22 0 35 0; +#X connect 21 0 34 0; +#X connect 22 0 34 0; #X connect 23 0 24 0; -#X connect 24 0 35 0; +#X connect 24 0 34 0; #X connect 25 0 26 0; -#X connect 26 0 35 0; +#X connect 26 0 34 0; #X connect 27 0 28 0; -#X connect 28 0 35 0; -#X connect 30 0 35 0; +#X connect 28 0 34 0; +#X connect 30 0 34 0; #X connect 33 0 31 0; #X connect 33 0 31 1; -#X connect 35 0 18 0; -#X connect 35 1 13 0; +#X connect 34 0 18 0; +#X connect 34 1 13 0; diff --git a/aka.wiiremote/aka.wiiremote.c b/aka.wiiremote/aka.wiiremote.c index d8b12cb..0831f44 100644 --- a/aka.wiiremote/aka.wiiremote.c +++ b/aka.wiiremote/aka.wiiremote.c @@ -81,7 +81,7 @@ char nunchukStr[] = "nunchuk"; char classicStr[] = "classic"; #ifdef PD -void setup_aka0x2ewiiremote() +void akawiiremote_setup() #else /* Max */ void main() #endif /* PD */ @@ -108,7 +108,7 @@ void main() #ifdef PD post("\tPd port by Hans-Christoph Steiner"); - akawiiremote_class = class_new(gensym("aka.wiiremote"), + akawiiremote_class = class_new(gensym("akawiiremote"), (t_newmethod)akawiiremote_new, (t_method)akawiiremote_free, sizeof(t_akawiiremote), @@ -597,10 +597,10 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) atom_string(av, x->address, MAXPDSTRING-1); IOReturn result = kIOReturnSuccess; - mach_port_t masterPort = NULL; + mach_port_t masterPort = (mach_port_t) NULL; result = IOMasterPort (bootstrap_port, &masterPort); if (kIOReturnSuccess != result) - pd_error("IOMasterPort error with bootstrap_port, error %d", result); + pd_error(x, "[akawiiremote] IOMasterPort error with bootstrap_port, error %d", result); else { // Create a notification port and add its run loop event source to our run loop -- cgit v1.2.1 From 7acd17222423c5ac84f3ad21a2ece9a2ef331c5d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 28 May 2008 10:54:53 +0000 Subject: moved files to reflect name change to [akawiiremote] svn path=/trunk/externals/io/; revision=9932 --- aka.wiiremote/aka.wiiremote-help.pd | 80 ------------------------------------- aka.wiiremote/akawiiremote-help.pd | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 80 deletions(-) delete mode 100644 aka.wiiremote/aka.wiiremote-help.pd create mode 100644 aka.wiiremote/akawiiremote-help.pd diff --git a/aka.wiiremote/aka.wiiremote-help.pd b/aka.wiiremote/aka.wiiremote-help.pd deleted file mode 100644 index c3ae89a..0000000 --- a/aka.wiiremote/aka.wiiremote-help.pd +++ /dev/null @@ -1,80 +0,0 @@ -#N canvas 287 96 744 626 10; -#X msg 128 207 connect; -#X msg 141 228 disconnect; -#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 127 285 metro 100; -#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 89 283 bang; -#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote -with your computer (only required for the first use).; -#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs -will start blinking.; -#X text 49 109 - Click on the [connect( message \, the LEDs will stop -blinking once its connected; -#X text 49 139 - Start the [metro] to get updates from [aka.wiiremote] -; -#X obj 399 526 pddp/print; -#X obj 354 556 pddp/print; -#X obj 354 410 route remote; -#X msg 503 290 getbattery; -#X msg 503 310 getled; -#X msg 503 330 getexpansion; -#X obj 489 431 print RIGHT; -#X obj 253 430 print LEFT; -#X obj 354 476 route motion buttons ir; -#X obj 444 497 pddp/print; -#X msg 294 224 ir \$1; -#X msg 218 225 motion \$1; -#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 344 224 vibration \$1; -#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 434 224 expansion \$1; -#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X msg 524 223 extraoutput \$1; -#N canvas 254 342 450 300 address 0; -#X obj 176 252 outlet; -#X msg 206 126 getaddress; -#X msg 176 72 address 00-1e-35-4c-e6-f1; -#X connect 1 0 0 0; -#X connect 2 0 0 0; -#X restore 25 462 pd address; -#X msg 503 352 getaddress; -#X obj 631 536 dac~; -#X obj 632 408 pddp/dsp; -#X obj 640 500 osc~ 100; -#X obj 303 388 akawiiremote; -#X connect 0 0 34 0; -#X connect 1 0 34 0; -#X connect 2 0 22 0; -#X connect 3 0 21 0; -#X connect 4 0 34 0; -#X connect 5 0 4 0; -#X connect 6 0 34 0; -#X connect 13 0 19 0; -#X connect 13 1 17 0; -#X connect 14 0 34 0; -#X connect 15 0 34 0; -#X connect 16 0 34 0; -#X connect 19 0 12 0; -#X connect 19 1 11 0; -#X connect 19 2 20 0; -#X connect 21 0 34 0; -#X connect 22 0 34 0; -#X connect 23 0 24 0; -#X connect 24 0 34 0; -#X connect 25 0 26 0; -#X connect 26 0 34 0; -#X connect 27 0 28 0; -#X connect 28 0 34 0; -#X connect 30 0 34 0; -#X connect 33 0 31 0; -#X connect 33 0 31 1; -#X connect 34 0 18 0; -#X connect 34 1 13 0; diff --git a/aka.wiiremote/akawiiremote-help.pd b/aka.wiiremote/akawiiremote-help.pd new file mode 100644 index 0000000..c3ae89a --- /dev/null +++ b/aka.wiiremote/akawiiremote-help.pd @@ -0,0 +1,80 @@ +#N canvas 287 96 744 626 10; +#X msg 128 207 connect; +#X msg 141 228 disconnect; +#X obj 218 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 294 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 127 285 metro 100; +#X obj 127 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 89 283 bang; +#X text 49 49 - Use the Bluetooth Setup Assistant to setup the WiiRemote +with your computer (only required for the first use).; +#X text 49 79 - Press the "Sync" button on the WiiRemote \, four LEDs +will start blinking.; +#X text 49 109 - Click on the [connect( message \, the LEDs will stop +blinking once its connected; +#X text 49 139 - Start the [metro] to get updates from [aka.wiiremote] +; +#X obj 399 526 pddp/print; +#X obj 354 556 pddp/print; +#X obj 354 410 route remote; +#X msg 503 290 getbattery; +#X msg 503 310 getled; +#X msg 503 330 getexpansion; +#X obj 489 431 print RIGHT; +#X obj 253 430 print LEFT; +#X obj 354 476 route motion buttons ir; +#X obj 444 497 pddp/print; +#X msg 294 224 ir \$1; +#X msg 218 225 motion \$1; +#X obj 344 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 344 224 vibration \$1; +#X obj 434 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 434 224 expansion \$1; +#X obj 524 202 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X msg 524 223 extraoutput \$1; +#N canvas 254 342 450 300 address 0; +#X obj 176 252 outlet; +#X msg 206 126 getaddress; +#X msg 176 72 address 00-1e-35-4c-e6-f1; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X restore 25 462 pd address; +#X msg 503 352 getaddress; +#X obj 631 536 dac~; +#X obj 632 408 pddp/dsp; +#X obj 640 500 osc~ 100; +#X obj 303 388 akawiiremote; +#X connect 0 0 34 0; +#X connect 1 0 34 0; +#X connect 2 0 22 0; +#X connect 3 0 21 0; +#X connect 4 0 34 0; +#X connect 5 0 4 0; +#X connect 6 0 34 0; +#X connect 13 0 19 0; +#X connect 13 1 17 0; +#X connect 14 0 34 0; +#X connect 15 0 34 0; +#X connect 16 0 34 0; +#X connect 19 0 12 0; +#X connect 19 1 11 0; +#X connect 19 2 20 0; +#X connect 21 0 34 0; +#X connect 22 0 34 0; +#X connect 23 0 24 0; +#X connect 24 0 34 0; +#X connect 25 0 26 0; +#X connect 26 0 34 0; +#X connect 27 0 28 0; +#X connect 28 0 34 0; +#X connect 30 0 34 0; +#X connect 33 0 31 0; +#X connect 33 0 31 1; +#X connect 34 0 18 0; +#X connect 34 1 13 0; -- cgit v1.2.1 From c095709343b24661506a5a850bac5cf142748a01 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 28 Jun 2008 16:08:02 +0000 Subject: first somewhat 'working' version of the objectclass to get data from the Sony SIXAXIS accelerometer svn path=/trunk/externals/io/; revision=10115 --- sixaxis/sixaxis-help.pd | 156 ++++++++++++++++++++++ sixaxis/sixaxis.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 501 insertions(+) create mode 100644 sixaxis/sixaxis-help.pd create mode 100644 sixaxis/sixaxis.c diff --git a/sixaxis/sixaxis-help.pd b/sixaxis/sixaxis-help.pd new file mode 100644 index 0000000..7b36070 --- /dev/null +++ b/sixaxis/sixaxis-help.pd @@ -0,0 +1,156 @@ +#N canvas 292 101 633 730 10; +#X obj 129 267 sixaxis /dev/hidraw0; +#X obj 107 178 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 18 178 metro 20; +#X obj 18 156 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X msg 38 156 stop; +#X obj 107 129 key; +#X obj 2 2 cnv 15 550 25 empty empty sixaxis 20 12 1 16 -228992 -66577 +0; +#X text 10 44 [sixaxis] outputs raw events from the Linux Event system. +It is used for access the output of various Human Interface Devices +\, like mice \, joysticks \, tablets \, etc.; +#X text 26 105 bang to get an update when polling is stopped.; +#X obj 107 149 sel 98; +#X text 153 149 <- (type 'b' for a bang); +#X obj 182 372 pddp/print; +#N canvas 743 25 411 235 see 0; +#N canvas 108 318 543 264 route 0; +#X obj 27 14 inlet; +#X obj 72 226 outlet; +#X obj 19 226 outlet; +#X obj 172 226 outlet; +#X obj 222 204 symbol; +#X obj 222 226 outlet; +#X obj 272 204 symbol; +#X obj 272 226 outlet; +#X obj 322 204 symbol; +#X obj 322 226 outlet; +#X obj 372 204 symbol; +#X obj 372 226 outlet; +#X obj 122 225 outlet; +#X obj 422 204 symbol; +#X obj 422 226 outlet; +#X obj 472 204 symbol; +#X obj 472 226 outlet; +#X obj 26 63 route open device poll total product manufacturer transport +type vendorID productID; +#X connect 0 0 17 0; +#X connect 4 0 5 0; +#X connect 6 0 7 0; +#X connect 8 0 9 0; +#X connect 10 0 11 0; +#X connect 13 0 14 0; +#X connect 15 0 16 0; +#X connect 17 0 2 0; +#X connect 17 1 1 0; +#X connect 17 2 12 0; +#X connect 17 3 3 0; +#X connect 17 4 4 0; +#X connect 17 5 6 0; +#X connect 17 6 8 0; +#X connect 17 7 10 0; +#X connect 17 8 13 0; +#X connect 17 9 15 0; +#X restore 117 70 pd route info; +#X obj 81 96 tgl 15 0 empty empty open 0 -6 0 8 -262144 -1 -1 1 1; +#X obj 110 22 inlet; +#X obj 123 43 print info; +#X symbolatom 304 93 0 0 0 0 productID - -; +#X symbolatom 304 112 0 0 0 0 vendorID - -; +#X symbolatom 304 151 0 0 0 0 transport - -; +#X symbolatom 304 171 0 0 0 0 manufacturer - -; +#X symbolatom 186 192 0 0 0 0 product - -; +#X floatatom 97 140 5 0 0 0 device - -; +#X floatatom 97 162 5 0 0 0 poll - -; +#X symbolatom 304 131 0 0 0 0 type - -; +#X floatatom 97 182 5 0 0 0 total - -; +#X connect 0 0 1 0; +#X connect 0 1 9 0; +#X connect 0 2 10 0; +#X connect 0 3 12 0; +#X connect 0 4 8 0; +#X connect 0 5 7 0; +#X connect 0 6 6 0; +#X connect 0 7 11 0; +#X connect 0 8 5 0; +#X connect 0 9 4 0; +#X connect 2 0 0 0; +#X connect 2 0 3 0; +#X restore 246 297 pd see device info; +#X obj 130 210 tgl 30 0 empty empty empty 17 7 0 10 -4034 -1 -1 0 1 +; +#X msg 179 222 info; +#X obj 181 348 spigot; +#X obj 216 328 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 249 334 spigot; +#X obj 282 327 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 250 354 print RAW; +#X obj 61 416 route position speed acceleration accelerometer; +#X obj 341 445 print WARNING_UNSUPPORTED_MESSAGES; +#X obj 43 528 unpack 0 0 0; +#X floatatom 31 549 7 0 0 0 - - -; +#X floatatom 77 549 7 0 0 0 - - -; +#X floatatom 123 549 7 0 0 0 - - -; +#X obj 77 484 unpack 0 0 0; +#X floatatom 65 505 7 0 0 0 - - -; +#X floatatom 111 505 7 0 0 0 - - -; +#X floatatom 157 505 7 0 0 0 - - -; +#X obj 197 461 unpack 0 0 0; +#X floatatom 185 482 7 0 0 0 - - -; +#X floatatom 231 482 7 0 0 0 - - -; +#X floatatom 277 482 7 0 0 0 - - -; +#X obj 252 513 track_min; +#X obj 325 517 track_max; +#X floatatom 324 539 9 0 0 0 - - -; +#X floatatom 252 539 9 0 0 0 - - -; +#X obj 22 573 track_min; +#X obj 95 577 track_max; +#X floatatom 94 599 9 0 0 0 - - -; +#X floatatom 22 599 9 0 0 0 - - -; +#X msg 176 551 bang; +#X msg 232 217 close; +#X connect 0 0 15 0; +#X connect 0 0 17 0; +#X connect 0 0 20 0; +#X connect 0 1 12 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 5 0 9 0; +#X connect 9 0 1 0; +#X connect 13 0 0 0; +#X connect 14 0 0 0; +#X connect 15 0 11 0; +#X connect 16 0 15 1; +#X connect 17 0 19 0; +#X connect 18 0 17 1; +#X connect 20 0 22 0; +#X connect 20 1 26 0; +#X connect 20 2 30 0; +#X connect 20 4 21 0; +#X connect 22 0 23 0; +#X connect 22 1 24 0; +#X connect 22 1 39 0; +#X connect 22 1 38 0; +#X connect 22 2 25 0; +#X connect 26 0 27 0; +#X connect 26 1 28 0; +#X connect 26 2 29 0; +#X connect 30 0 31 0; +#X connect 30 1 32 0; +#X connect 30 1 35 0; +#X connect 30 1 34 0; +#X connect 30 2 33 0; +#X connect 34 0 37 0; +#X connect 35 0 36 0; +#X connect 38 0 41 0; +#X connect 39 0 40 0; +#X connect 42 0 39 2; +#X connect 42 0 38 2; +#X connect 43 0 0 0; diff --git a/sixaxis/sixaxis.c b/sixaxis/sixaxis.c new file mode 100644 index 0000000..b9c2232 --- /dev/null +++ b/sixaxis/sixaxis.c @@ -0,0 +1,345 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "m_pd.h" + +#define DEBUG(x) +//#define DEBUG(x) x + +#define DEFAULT_DELAY 10 +#define SIXAXIS_DEVICE "/dev/hidraw0" + +static char *version = "$Revision: 1.1 $"; + +/*------------------------------------------------------------------------------ + * GLOBAL DECLARATIONS + */ + +/* hidraw data format */ +struct sixaxis_state { + double time; + int ax, ay, az; // Raw accelerometer data + double ddx, ddy, ddz; // Acceleration + double dx, dy, dz; // Speed + double x, y, z; // Position +}; + +/* pre-generated symbols */ +static t_symbol *ps_open, *ps_device, *ps_poll, *ps_total, *ps_range; +static t_symbol *ps_accelerometer, *ps_acceleration, *ps_speed, *ps_position; + +/* mostly for status querying */ +static unsigned short device_count; + +/* previous state for calculating position, speed, acceleration */ +static struct sixaxis_state prev; + +/*------------------------------------------------------------------------------ + * CLASS DEF + */ +static t_class *sixaxis_class; + +typedef struct _sixaxis { + t_object x_obj; + t_int x_fd; + t_symbol *x_devname; + t_clock *x_clock; + short x_device_number; + short x_instance; + t_int x_device_open; + int x_read_ok; + int x_started; + int x_delay; + unsigned char buf[128]; + struct sixaxis_state x_sixaxis_state; + t_atom x_output_atoms[3]; + t_outlet *x_data_outlet; + t_outlet *x_status_outlet; +} t_sixaxis; + + + +/*------------------------------------------------------------------------------ + * SUPPORT FUNCTIONS + */ + +static void output_status(t_sixaxis *x, t_symbol *selector, t_float output_value) +{ + t_atom *output_atom = (t_atom *)getbytes(sizeof(t_atom)); + SETFLOAT(output_atom, output_value); + outlet_anything( x->x_status_outlet, selector, 1, output_atom); + freebytes(output_atom,sizeof(t_atom)); +} + +static void output_open_status(t_sixaxis *x) +{ + output_status(x, ps_open, x->x_device_open); +} + +static void output_device_number(t_sixaxis *x) +{ + output_status(x, ps_device, x->x_device_number); +} + +static void output_poll_time(t_sixaxis *x) +{ + output_status(x, ps_poll, x->x_delay); +} + +static void output_device_count(t_sixaxis *x) +{ + output_status(x, ps_total, device_count); +} + +/*------------------------------------------------------------------------------ + * CLASS METHODS + */ + +void sixaxis_stop(t_sixaxis* x) +{ + DEBUG(post("sixaxis_stop");); + + if (x->x_fd >= 0 && x->x_started) { + clock_unset(x->x_clock); + post("sixaxis: polling stopped"); + x->x_started = 0; + } +} + +static void sixaxis_close(t_sixaxis *x) +{ + DEBUG(post("sixaxis_close");); + +/* just to be safe, stop it first */ + sixaxis_stop(x); + + if(x->x_fd < 0) + return; + close(x->x_fd); + post("[sixaxis] closed %s",x->x_devname->s_name); + x->x_device_open = 0; + output_open_status(x); +} + +static int sixaxis_open(t_sixaxis *x, t_symbol *s) +{ + DEBUG(post("sixaxis_open");); + + sixaxis_close(x); + + /* set obj device name to parameter + * otherwise set to default + */ + if (s != &s_) + x->x_devname = s; + + /* open device */ + if (x->x_devname) { + /* open the device read-only, non-exclusive */ + x->x_fd = open(x->x_devname->s_name, O_RDONLY | O_NONBLOCK); + /* test if device open */ + if (x->x_fd > -1 ) { + x->x_device_open = 1; + output_open_status(x); + return 1; + } else { + pd_error(x, "[sixaxis] open %s failed", x->x_devname->s_name); + x->x_fd = -1; + x->x_device_open = 0; + output_open_status(x); + } + } + return 0; +} + +static void sixaxis_read(t_sixaxis *x) +{ + if(x->x_fd < 0) + return; + if(read(x->x_fd, &(x->buf), sizeof(x->buf)) > -1) { +// if ( nr < 0 ) { perror("read(stdin)"); exit(1); } +// if ( nr != 48 ) { fprintf(stderr, "Unsupported report\n"); exit(1); } + + struct timeval tv; + if ( gettimeofday(&tv, NULL) ) { + perror("gettimeofday"); + return; + } + x->x_sixaxis_state.time = tv.tv_sec + tv.tv_usec*1e-6; + x->x_sixaxis_state.ax = x->buf[40]<<8 | x->buf[41]; + x->x_sixaxis_state.ay = x->buf[42]<<8 | x->buf[43]; + x->x_sixaxis_state.az = x->buf[44]<<8 | x->buf[45]; + if ( ! prev.time ) { + prev.time = x->x_sixaxis_state.time; + prev.ax = x->x_sixaxis_state.ax; + prev.ay = x->x_sixaxis_state.ay; + prev.az = x->x_sixaxis_state.az; + } + double dt = x->x_sixaxis_state.time - prev.time; + double rc_dd = 2.0; // Time constant for highpass filter on acceleration + double alpha_dd = rc_dd / (rc_dd+dt); + x->x_sixaxis_state.ddx = alpha_dd*(prev.ddx + (x->x_sixaxis_state.ax-prev.ax)*0.01); + x->x_sixaxis_state.ddy = alpha_dd*(prev.ddy + (x->x_sixaxis_state.ay-prev.ay)*0.01); + x->x_sixaxis_state.ddz = alpha_dd*(prev.ddz - (x->x_sixaxis_state.az-prev.az)*0.01); + double rc_d = 2.0; // Time constant for highpass filter on speed + double alpha_d = rc_d / (rc_d+dt); + x->x_sixaxis_state.dx = alpha_d*(prev.dx + x->x_sixaxis_state.ddx*dt); + x->x_sixaxis_state.dy = alpha_d*(prev.dy + x->x_sixaxis_state.ddy*dt); + x->x_sixaxis_state.dz = alpha_d*(prev.dz + x->x_sixaxis_state.ddz*dt); + double rc = 1.0; // Time constant for highpass filter on position + double alpha = rc / (rc+dt); + x->x_sixaxis_state.x = alpha*(prev.x + x->x_sixaxis_state.dx*dt); + x->x_sixaxis_state.y = alpha*(prev.y + x->x_sixaxis_state.dy*dt); + x->x_sixaxis_state.z = alpha*(prev.z + x->x_sixaxis_state.dz*dt); + /* raw accelerometer data */ + SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.ax); + SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.ay); + SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.az); + outlet_anything(x->x_data_outlet, ps_accelerometer, 3, x->x_output_atoms); + /* acceleration data */ + SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.ddx); + SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.ddy); + SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.ddz); + outlet_anything(x->x_data_outlet, ps_acceleration, 3, x->x_output_atoms); + /* speed data */ + SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.dx); + SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.dy); + SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.dz); + outlet_anything(x->x_data_outlet, ps_speed, 3, x->x_output_atoms); + /* position data */ + SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.x); + SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.y); + SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.z); + outlet_anything(x->x_data_outlet, ps_position, 3, x->x_output_atoms); + } + if(x->x_started) { + clock_delay(x->x_clock, x->x_delay); + } +} +// double ddx, ddy, ddz; // Acceleration +// double dx, dy, dz; // Speed +// double x, y, z; // Position + +/* Actions */ + +static void sixaxis_info(t_sixaxis *x) +{ + output_open_status(x); + output_device_number(x); + output_device_count(x); + output_poll_time(x); +// TODO output ranges for sixaxis +// output_element_ranges(x); +} + +void sixaxis_start(t_sixaxis* x) +{ + DEBUG(post("sixaxis_start");); + + if (x->x_fd > -1 && !x->x_started) { + clock_delay(x->x_clock, DEFAULT_DELAY); + post("sixaxis: polling started"); + x->x_started = 1; + } else { + post("You need to set a input device (i.e /dev/input/event0)"); + } + + if(x->x_device_number > -1) + { + if(!x->x_device_open) + { + sixaxis_open(x,x->x_devname); + } + if(!x->x_started) + { + clock_delay(x->x_clock, x->x_delay); + x->x_started = 1; + } + } + +} + +static void sixaxis_float(t_sixaxis* x, t_floatarg f) +{ + DEBUG(post("sixaxis_float");); + + if (f > 0) + sixaxis_start(x); + else + sixaxis_stop(x); +} + +/* setup functions */ +static void sixaxis_free(t_sixaxis* x) +{ + DEBUG(post("sixaxis_free");); + + if (x->x_fd < 0) return; + + sixaxis_stop(x); + clock_free(x->x_clock); + close(x->x_fd); +} + +static void *sixaxis_new(t_symbol *s) +{ + t_sixaxis *x = (t_sixaxis *)pd_new(sixaxis_class); + + DEBUG(post("sixaxis_new");); + + post("[sixaxis] %s, written by Hans-Christoph Steiner ",version); + + /* init vars */ + x->x_fd = -1; + x->x_read_ok = 1; + x->x_started = 0; + x->x_delay = DEFAULT_DELAY; + x->x_devname = gensym(SIXAXIS_DEVICE); + + x->x_clock = clock_new(x, (t_method)sixaxis_read); + + /* create standard hidio-style outlets */ + x->x_data_outlet = outlet_new(&x->x_obj, 0); + x->x_status_outlet = outlet_new(&x->x_obj, 0); + + /* set to the value from the object argument, if that exists */ + if (s != &s_) + x->x_devname = s; + + return (x); +} + +void sixaxis_setup(void) +{ + DEBUG(post("sixaxis_setup");); + sixaxis_class = class_new(gensym("sixaxis"), + (t_newmethod)sixaxis_new, + (t_method)sixaxis_free, + sizeof(t_sixaxis), 0, A_DEFSYM, 0); + + /* add inlet datatype methods */ + class_addfloat(sixaxis_class,(t_method) sixaxis_float); + class_addbang(sixaxis_class,(t_method) sixaxis_read); + + /* add inlet message methods */ + class_addmethod(sixaxis_class,(t_method) sixaxis_open,gensym("open"),A_DEFFLOAT,0); + class_addmethod(sixaxis_class,(t_method) sixaxis_close,gensym("close"),0); + class_addmethod(sixaxis_class,(t_method) sixaxis_info,gensym("info"),0); + + /* pre-generate often used symbols */ + ps_open = gensym("open"); + ps_device = gensym("device"); + ps_poll = gensym("poll"); + ps_total = gensym("total"); + ps_range = gensym("range"); + ps_accelerometer = gensym("accelerometer"); + ps_acceleration = gensym("acceleration"); + ps_speed = gensym("speed"); + ps_position = gensym("position"); +} + -- cgit v1.2.1 From 8d8c3b56bd45eb78a3d70b61d00d0e14290e6178 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 28 Jun 2008 21:32:30 +0000 Subject: - the sixaxis external now builds with Pd-extended, and outputs the raw accelerometer data - for the rest of the data, use [hid] or [hidio] they happily coexist svn path=/trunk/externals/io/; revision=10116 --- sixaxis/Makefile | 17 +++ sixaxis/sixaxis-help.pd | 193 ++++++++++++++------------------- sixaxis/sixaxis.c | 279 ++++++++++++++++++++++++++++++------------------ 3 files changed, 272 insertions(+), 217 deletions(-) create mode 100644 sixaxis/Makefile diff --git a/sixaxis/Makefile b/sixaxis/Makefile new file mode 100644 index 0000000..2b8688b --- /dev/null +++ b/sixaxis/Makefile @@ -0,0 +1,17 @@ +TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') +EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') + +default: + make -C $(EXTERNALS_ROOT) $(TARGET) + +install: + make -C $(EXTERNALS_ROOT) $(TARGET)_install + +clean: + make -C $(EXTERNALS_ROOT) $(TARGET)_clean + +test_locations: + make -C $(EXTERNALS_ROOT) test_locations + +etags: + etags *.[ch] ~/code/pure-data/trunk/pd/src/*.[ch] /usr/include/*.h /usr/include/sys/*.h diff --git a/sixaxis/sixaxis-help.pd b/sixaxis/sixaxis-help.pd index 7b36070..b5fae4f 100644 --- a/sixaxis/sixaxis-help.pd +++ b/sixaxis/sixaxis-help.pd @@ -1,22 +1,7 @@ -#N canvas 292 101 633 730 10; -#X obj 129 267 sixaxis /dev/hidraw0; -#X obj 107 178 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 --1; -#X obj 18 178 metro 20; -#X obj 18 156 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 --1; -#X msg 38 156 stop; -#X obj 107 129 key; -#X obj 2 2 cnv 15 550 25 empty empty sixaxis 20 12 1 16 -228992 -66577 +#N canvas 197 95 565 482 10; +#X obj -71 5 cnv 15 550 25 empty empty sixaxis 20 12 1 16 -228992 -66577 0; -#X text 10 44 [sixaxis] outputs raw events from the Linux Event system. -It is used for access the output of various Human Interface Devices -\, like mice \, joysticks \, tablets \, etc.; -#X text 26 105 bang to get an update when polling is stopped.; -#X obj 107 149 sel 98; -#X text 153 149 <- (type 'b' for a bang); -#X obj 182 372 pddp/print; -#N canvas 743 25 411 235 see 0; +#N canvas 746 51 411 235 see 0; #N canvas 108 318 543 264 route 0; #X obj 27 14 inlet; #X obj 72 226 outlet; @@ -55,102 +40,88 @@ type vendorID productID; #X connect 17 8 13 0; #X connect 17 9 15 0; #X restore 117 70 pd route info; -#X obj 81 96 tgl 15 0 empty empty open 0 -6 0 8 -262144 -1 -1 1 1; +#X obj 221 96 tgl 15 0 empty empty open 0 -6 0 8 -262144 -1 -1 1 1 +; #X obj 110 22 inlet; #X obj 123 43 print info; -#X symbolatom 304 93 0 0 0 0 productID - -; -#X symbolatom 304 112 0 0 0 0 vendorID - -; -#X symbolatom 304 151 0 0 0 0 transport - -; -#X symbolatom 304 171 0 0 0 0 manufacturer - -; -#X symbolatom 186 192 0 0 0 0 product - -; -#X floatatom 97 140 5 0 0 0 device - -; -#X floatatom 97 162 5 0 0 0 poll - -; -#X symbolatom 304 131 0 0 0 0 type - -; -#X floatatom 97 182 5 0 0 0 total - -; +#X floatatom 156 140 5 0 0 0 device - -; +#X floatatom 156 162 5 0 0 0 poll - -; +#X floatatom 156 182 5 0 0 0 total - -; #X connect 0 0 1 0; -#X connect 0 1 9 0; -#X connect 0 2 10 0; -#X connect 0 3 12 0; -#X connect 0 4 8 0; -#X connect 0 5 7 0; -#X connect 0 6 6 0; -#X connect 0 7 11 0; -#X connect 0 8 5 0; -#X connect 0 9 4 0; +#X connect 0 1 4 0; +#X connect 0 2 5 0; +#X connect 0 3 6 0; #X connect 2 0 0 0; #X connect 2 0 3 0; -#X restore 246 297 pd see device info; -#X obj 130 210 tgl 30 0 empty empty empty 17 7 0 10 -4034 -1 -1 0 1 +#X restore 82 239 pd see device info; +#X obj -7 181 tgl 30 0 empty empty empty 17 7 0 10 -4034 -1 -1 0 1 ; -#X msg 179 222 info; -#X obj 181 348 spigot; -#X obj 216 328 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 249 334 spigot; -#X obj 282 327 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 250 354 print RAW; -#X obj 61 416 route position speed acceleration accelerometer; -#X obj 341 445 print WARNING_UNSUPPORTED_MESSAGES; -#X obj 43 528 unpack 0 0 0; -#X floatatom 31 549 7 0 0 0 - - -; -#X floatatom 77 549 7 0 0 0 - - -; -#X floatatom 123 549 7 0 0 0 - - -; -#X obj 77 484 unpack 0 0 0; -#X floatatom 65 505 7 0 0 0 - - -; -#X floatatom 111 505 7 0 0 0 - - -; -#X floatatom 157 505 7 0 0 0 - - -; -#X obj 197 461 unpack 0 0 0; -#X floatatom 185 482 7 0 0 0 - - -; -#X floatatom 231 482 7 0 0 0 - - -; -#X floatatom 277 482 7 0 0 0 - - -; -#X obj 252 513 track_min; -#X obj 325 517 track_max; -#X floatatom 324 539 9 0 0 0 - - -; -#X floatatom 252 539 9 0 0 0 - - -; -#X obj 22 573 track_min; -#X obj 95 577 track_max; -#X floatatom 94 599 9 0 0 0 - - -; -#X floatatom 22 599 9 0 0 0 - - -; -#X msg 176 551 bang; -#X msg 232 217 close; -#X connect 0 0 15 0; -#X connect 0 0 17 0; -#X connect 0 0 20 0; -#X connect 0 1 12 0; -#X connect 1 0 0 0; -#X connect 2 0 0 0; -#X connect 3 0 2 0; -#X connect 4 0 2 0; -#X connect 5 0 9 0; -#X connect 9 0 1 0; -#X connect 13 0 0 0; -#X connect 14 0 0 0; -#X connect 15 0 11 0; -#X connect 16 0 15 1; -#X connect 17 0 19 0; -#X connect 18 0 17 1; -#X connect 20 0 22 0; -#X connect 20 1 26 0; -#X connect 20 2 30 0; -#X connect 20 4 21 0; -#X connect 22 0 23 0; -#X connect 22 1 24 0; -#X connect 22 1 39 0; -#X connect 22 1 38 0; -#X connect 22 2 25 0; -#X connect 26 0 27 0; -#X connect 26 1 28 0; -#X connect 26 2 29 0; -#X connect 30 0 31 0; -#X connect 30 1 32 0; -#X connect 30 1 35 0; -#X connect 30 1 34 0; -#X connect 30 2 33 0; -#X connect 34 0 37 0; -#X connect 35 0 36 0; -#X connect 38 0 41 0; -#X connect 39 0 40 0; -#X connect 42 0 39 2; -#X connect 42 0 38 2; -#X connect 43 0 0 0; +#X msg 89 188 info; +#X msg 48 171 close; +#X obj -20 406 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 5904 1; +#X obj 120 406 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 8699 1; +#X obj 260 406 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 5152 1; +#X obj 43 276 route accelerometer; +#X obj 43 308 route x y z; +#X msg 43 151 open 4; +#N canvas 162 133 570 420 serin 0; +#X obj 286 61 cnv 15 30 15 empty \$0-open-canvas 4 4 8 0 14 -233017 +-1 0; +#X obj 60 61 hradio 15 1 1 15 empty empty empty 0 -6 0 8 -225271 -1 +-1 4; +#X obj 60 13 inlet; +#X msg 200 202 label \$1; +#X obj 200 180 makefilename %d; +#X obj 59 108 int; +#X obj 59 337 outlet; +#X msg 201 306 set \$1 \$2; +#X obj 59 266 trigger bang anything; +#X obj 201 286 list; +#X msg 60 210 open \$1; +#X obj 200 225 send \$0-open-canvas; +#X connect 1 0 5 0; +#X connect 2 0 1 0; +#X connect 3 0 11 0; +#X connect 4 0 3 0; +#X connect 5 0 4 0; +#X connect 5 0 10 0; +#X connect 7 0 6 0; +#X connect 8 0 6 0; +#X connect 8 1 9 0; +#X connect 9 0 7 0; +#X connect 10 0 8 0; +#X coords 0 -1 1 1 257 17 1 60 60; +#X restore 43 129 pd serin; +#X obj 257 375 mapping/autoscale; +#X obj 117 375 mapping/autoscale; +#X obj -23 375 mapping/autoscale; +#X obj 43 216 sixaxis; +#N canvas 6 77 450 300 more 0; +#X text -17 56 By default \, [sixaxis] uses /dev/hidraw? for the device +name to get data from. You can override it using the [devname( message +\, like this:; +#X msg 30 154 devname /dev/my/strange/custom/hidraw; +#X restore -15 444 pd more on device names; +#X text -63 44 This objectclass supports getting accelerometer data +from the Sony SIXAXIS controller. Use this in conjuction with [hid] +to get all of the data from the SIXAXIS; +#X obj -59 83 pddp/pddplink http://www.pabr.org/sixlinux/sixlinux.en.html +-text Using the PlayStation 3 controller in Bluetooth mode with Linux +; +#X connect 2 0 15 0; +#X connect 3 0 15 0; +#X connect 4 0 15 0; +#X connect 8 0 9 0; +#X connect 9 0 14 0; +#X connect 9 1 13 0; +#X connect 9 2 12 0; +#X connect 10 0 15 0; +#X connect 11 0 10 0; +#X connect 12 0 7 0; +#X connect 13 0 6 0; +#X connect 14 0 5 0; +#X connect 15 0 8 0; +#X connect 15 1 1 0; diff --git a/sixaxis/sixaxis.c b/sixaxis/sixaxis.c index b9c2232..d110c71 100644 --- a/sixaxis/sixaxis.c +++ b/sixaxis/sixaxis.c @@ -4,15 +4,16 @@ #include #include #include +#include #include #include "m_pd.h" -#define DEBUG(x) -//#define DEBUG(x) x +//#define DEBUG(x) +#define DEBUG(x) x #define DEFAULT_DELAY 10 -#define SIXAXIS_DEVICE "/dev/hidraw0" +#define SIXAXIS_DEVNAME "/dev/hidraw" static char *version = "$Revision: 1.1 $"; @@ -30,14 +31,15 @@ struct sixaxis_state { }; /* pre-generated symbols */ -static t_symbol *ps_open, *ps_device, *ps_poll, *ps_total, *ps_range; +static t_symbol *ps_open, *ps_device, *ps_poll, *ps_total, *ps_range, *ps_devname; +static t_symbol *ps_x, *ps_y, *ps_z; static t_symbol *ps_accelerometer, *ps_acceleration, *ps_speed, *ps_position; /* mostly for status querying */ static unsigned short device_count; /* previous state for calculating position, speed, acceleration */ -static struct sixaxis_state prev; +//static struct sixaxis_state prev; /*------------------------------------------------------------------------------ * CLASS DEF @@ -47,7 +49,6 @@ static t_class *sixaxis_class; typedef struct _sixaxis { t_object x_obj; t_int x_fd; - t_symbol *x_devname; t_clock *x_clock; short x_device_number; short x_instance; @@ -96,6 +97,21 @@ static void output_device_count(t_sixaxis *x) output_status(x, ps_total, device_count); } +static short get_device_number_from_arguments(int argc, t_atom *argv) +{ + short device_number = -1; + t_symbol *first_argument; + + if(argc == 1) + { + first_argument = atom_getsymbolarg(0,argc,argv); + if(first_argument == &s_) + { // single float arg means device # + device_number = (short) atom_getfloatarg(0,argc,argv); + } + } + return device_number; +} /*------------------------------------------------------------------------------ * CLASS METHODS */ @@ -121,40 +137,90 @@ static void sixaxis_close(t_sixaxis *x) if(x->x_fd < 0) return; close(x->x_fd); - post("[sixaxis] closed %s",x->x_devname->s_name); + post("[sixaxis] closed %s%d", SIXAXIS_DEVNAME, x->x_device_number); x->x_device_open = 0; output_open_status(x); } -static int sixaxis_open(t_sixaxis *x, t_symbol *s) +static t_int sixaxis_open_device(t_sixaxis *x, short device_number) { - DEBUG(post("sixaxis_open");); + DEBUG(post("sixaxis_open_device");); - sixaxis_close(x); + char block_device[FILENAME_MAX]; - /* set obj device name to parameter - * otherwise set to default - */ - if (s != &s_) - x->x_devname = s; - - /* open device */ - if (x->x_devname) { - /* open the device read-only, non-exclusive */ - x->x_fd = open(x->x_devname->s_name, O_RDONLY | O_NONBLOCK); - /* test if device open */ - if (x->x_fd > -1 ) { + x->x_fd = -1; + + if(device_number < 0) + { + pd_error(x,"[sixaxis] invalid device number: %d (must be 0 or greater)" + , device_number); + return EXIT_FAILURE; + } + + x->x_device_number = device_number; + snprintf(block_device, FILENAME_MAX, "%s%d", SIXAXIS_DEVNAME, x->x_device_number); + + /* open the device read-only, non-exclusive */ + x->x_fd = open(block_device, O_RDONLY | O_NONBLOCK); + /* test if device open */ + if(x->x_fd < 0 ) + { + pd_error(x,"[sixaxis] open %s failed",block_device); + x->x_fd = -1; + return EXIT_FAILURE; + } + post ("[sixaxis] opened device %d (%s)", x->x_device_number, block_device); + + return EXIT_SUCCESS; +} + +/* sixaxis_open behavoir + * current state action + * --------------------------------------- + * closed / same device open + * open / same device no action + * closed / different device open + * open / different device close, open + */ +static void sixaxis_open(t_sixaxis *x, t_symbol *s, int argc, t_atom *argv) +{ + DEBUG(post("sixaxis_open");); + short new_device_number = get_device_number_from_arguments(argc, argv); +// t_int started = x->x_started; // store state to restore after device is opened + + if (new_device_number < 0) + { + pd_error(x,"[sixaxis] invalid device number: %d (must be 0 or greater)", + new_device_number); + return; + } + /* check whether we have to close previous device */ + if (x->x_device_open && new_device_number != x->x_device_number) + { + sixaxis_close(x); + } + /* no device open, so open one now */ + if (!x->x_device_open) + { + if(sixaxis_open_device(x, new_device_number) == EXIT_SUCCESS) + { x->x_device_open = 1; - output_open_status(x); - return 1; - } else { - pd_error(x, "[sixaxis] open %s failed", x->x_devname->s_name); - x->x_fd = -1; - x->x_device_open = 0; - output_open_status(x); + x->x_device_number = new_device_number; + /* restore the polling state so that when I [tgl] is used to + * start/stop [sixaxis], the [tgl]'s state will continue to + * accurately reflect [sixaxis]'s state */ + post("[sixaxis] set device# to %d",new_device_number); + output_device_number(x); + } + else + { + x->x_device_number = -1; + pd_error(x, "[sixaxis] can not open device %d",new_device_number); } } - return 0; + + /* always output open result so you can test for success in Pd space */ + output_open_status(x); } static void sixaxis_read(t_sixaxis *x) @@ -165,57 +231,66 @@ static void sixaxis_read(t_sixaxis *x) // if ( nr < 0 ) { perror("read(stdin)"); exit(1); } // if ( nr != 48 ) { fprintf(stderr, "Unsupported report\n"); exit(1); } - struct timeval tv; - if ( gettimeofday(&tv, NULL) ) { - perror("gettimeofday"); - return; - } - x->x_sixaxis_state.time = tv.tv_sec + tv.tv_usec*1e-6; - x->x_sixaxis_state.ax = x->buf[40]<<8 | x->buf[41]; - x->x_sixaxis_state.ay = x->buf[42]<<8 | x->buf[43]; - x->x_sixaxis_state.az = x->buf[44]<<8 | x->buf[45]; - if ( ! prev.time ) { - prev.time = x->x_sixaxis_state.time; - prev.ax = x->x_sixaxis_state.ax; - prev.ay = x->x_sixaxis_state.ay; - prev.az = x->x_sixaxis_state.az; - } - double dt = x->x_sixaxis_state.time - prev.time; - double rc_dd = 2.0; // Time constant for highpass filter on acceleration - double alpha_dd = rc_dd / (rc_dd+dt); - x->x_sixaxis_state.ddx = alpha_dd*(prev.ddx + (x->x_sixaxis_state.ax-prev.ax)*0.01); - x->x_sixaxis_state.ddy = alpha_dd*(prev.ddy + (x->x_sixaxis_state.ay-prev.ay)*0.01); - x->x_sixaxis_state.ddz = alpha_dd*(prev.ddz - (x->x_sixaxis_state.az-prev.az)*0.01); - double rc_d = 2.0; // Time constant for highpass filter on speed - double alpha_d = rc_d / (rc_d+dt); - x->x_sixaxis_state.dx = alpha_d*(prev.dx + x->x_sixaxis_state.ddx*dt); - x->x_sixaxis_state.dy = alpha_d*(prev.dy + x->x_sixaxis_state.ddy*dt); - x->x_sixaxis_state.dz = alpha_d*(prev.dz + x->x_sixaxis_state.ddz*dt); - double rc = 1.0; // Time constant for highpass filter on position - double alpha = rc / (rc+dt); - x->x_sixaxis_state.x = alpha*(prev.x + x->x_sixaxis_state.dx*dt); - x->x_sixaxis_state.y = alpha*(prev.y + x->x_sixaxis_state.dy*dt); - x->x_sixaxis_state.z = alpha*(prev.z + x->x_sixaxis_state.dz*dt); +/* struct timeval tv; */ +/* if ( gettimeofday(&tv, NULL) ) { */ +/* perror("gettimeofday"); */ +/* return; */ +/* } */ +/* x->x_sixaxis_state.time = tv.tv_sec + tv.tv_usec*1e-6; */ +/* x->x_sixaxis_state.ax = x->buf[40]<<8 | x->buf[41]; */ +/* x->x_sixaxis_state.ay = x->buf[42]<<8 | x->buf[43]; */ +/* x->x_sixaxis_state.az = x->buf[44]<<8 | x->buf[45]; */ +/* if ( ! prev.time ) { */ +/* prev.time = x->x_sixaxis_state.time; */ +/* prev.ax = x->x_sixaxis_state.ax; */ +/* prev.ay = x->x_sixaxis_state.ay; */ +/* prev.az = x->x_sixaxis_state.az; */ +/* } */ +/* double dt = x->x_sixaxis_state.time - prev.time; */ +/* double rc_dd = 2.0; // Time constant for highpass filter on acceleration */ +/* double alpha_dd = rc_dd / (rc_dd+dt); */ +/* x->x_sixaxis_state.ddx = alpha_dd*(prev.ddx + (x->x_sixaxis_state.ax-prev.ax)*0.01); */ +/* x->x_sixaxis_state.ddy = alpha_dd*(prev.ddy + (x->x_sixaxis_state.ay-prev.ay)*0.01); */ +/* x->x_sixaxis_state.ddz = alpha_dd*(prev.ddz - (x->x_sixaxis_state.az-prev.az)*0.01); */ +/* double rc_d = 2.0; // Time constant for highpass filter on speed */ +/* double alpha_d = rc_d / (rc_d+dt); */ +/* x->x_sixaxis_state.dx = alpha_d*(prev.dx + x->x_sixaxis_state.ddx*dt); */ +/* x->x_sixaxis_state.dy = alpha_d*(prev.dy + x->x_sixaxis_state.ddy*dt); */ +/* x->x_sixaxis_state.dz = alpha_d*(prev.dz + x->x_sixaxis_state.ddz*dt); */ +/* double rc = 1.0; // Time constant for highpass filter on position */ +/* double alpha = rc / (rc+dt); */ +/* x->x_sixaxis_state.x = alpha*(prev.x + x->x_sixaxis_state.dx*dt); */ +/* x->x_sixaxis_state.y = alpha*(prev.y + x->x_sixaxis_state.dy*dt); */ +/* x->x_sixaxis_state.z = alpha*(prev.z + x->x_sixaxis_state.dz*dt); */ /* raw accelerometer data */ - SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.ax); - SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.ay); - SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.az); - outlet_anything(x->x_data_outlet, ps_accelerometer, 3, x->x_output_atoms); - /* acceleration data */ - SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.ddx); - SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.ddy); - SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.ddz); - outlet_anything(x->x_data_outlet, ps_acceleration, 3, x->x_output_atoms); - /* speed data */ - SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.dx); - SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.dy); - SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.dz); - outlet_anything(x->x_data_outlet, ps_speed, 3, x->x_output_atoms); - /* position data */ - SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.x); - SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.y); - SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.z); - outlet_anything(x->x_data_outlet, ps_position, 3, x->x_output_atoms); + SETSYMBOL(x->x_output_atoms, ps_x); + SETFLOAT(x->x_output_atoms + 1, x->buf[40]<<8 | x->buf[41]); + outlet_anything(x->x_data_outlet, ps_accelerometer, 2, x->x_output_atoms); + SETSYMBOL(x->x_output_atoms, ps_y); + SETFLOAT(x->x_output_atoms + 1, x->buf[42]<<8 | x->buf[43]); + outlet_anything(x->x_data_outlet, ps_accelerometer, 2, x->x_output_atoms); + SETSYMBOL(x->x_output_atoms, ps_z); + SETFLOAT(x->x_output_atoms + 1, x->buf[44]<<8 | x->buf[45]); + outlet_anything(x->x_data_outlet, ps_accelerometer, 2, x->x_output_atoms); +/* SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.ax); */ +/* SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.ay); */ +/* SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.az); */ +/* outlet_anything(x->x_data_outlet, ps_accelerometer, 3, x->x_output_atoms); */ +/* /\* acceleration data *\/ */ +/* SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.ddx); */ +/* SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.ddy); */ +/* SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.ddz); */ +/* outlet_anything(x->x_data_outlet, ps_acceleration, 3, x->x_output_atoms); */ +/* /\* speed data *\/ */ +/* SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.dx); */ +/* SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.dy); */ +/* SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.dz); */ +/* outlet_anything(x->x_data_outlet, ps_speed, 3, x->x_output_atoms); */ +/* /\* position data *\/ */ +/* SETFLOAT(x->x_output_atoms, x->x_sixaxis_state.x); */ +/* SETFLOAT(x->x_output_atoms + 1, x->x_sixaxis_state.y); */ +/* SETFLOAT(x->x_output_atoms + 2, x->x_sixaxis_state.z); */ +/* outlet_anything(x->x_data_outlet, ps_position, 3, x->x_output_atoms); */ } if(x->x_started) { clock_delay(x->x_clock, x->x_delay); @@ -240,28 +315,15 @@ static void sixaxis_info(t_sixaxis *x) void sixaxis_start(t_sixaxis* x) { DEBUG(post("sixaxis_start");); - + + if(!x->x_device_open) { + sixaxis_open_device(x, x->x_device_number); + } if (x->x_fd > -1 && !x->x_started) { clock_delay(x->x_clock, DEFAULT_DELAY); post("sixaxis: polling started"); x->x_started = 1; - } else { - post("You need to set a input device (i.e /dev/input/event0)"); } - - if(x->x_device_number > -1) - { - if(!x->x_device_open) - { - sixaxis_open(x,x->x_devname); - } - if(!x->x_started) - { - clock_delay(x->x_clock, x->x_delay); - x->x_started = 1; - } - } - } static void sixaxis_float(t_sixaxis* x, t_floatarg f) @@ -286,7 +348,7 @@ static void sixaxis_free(t_sixaxis* x) close(x->x_fd); } -static void *sixaxis_new(t_symbol *s) +static void *sixaxis_new(t_symbol *s, int argc, t_atom *argv) { t_sixaxis *x = (t_sixaxis *)pd_new(sixaxis_class); @@ -299,17 +361,16 @@ static void *sixaxis_new(t_symbol *s) x->x_read_ok = 1; x->x_started = 0; x->x_delay = DEFAULT_DELAY; - x->x_devname = gensym(SIXAXIS_DEVICE); + if(argc > 0) + x->x_device_number = get_device_number_from_arguments(argc, argv); + else + x->x_device_number = 0; x->x_clock = clock_new(x, (t_method)sixaxis_read); - /* create standard hidio-style outlets */ + /* create standard "io"-style outlets */ x->x_data_outlet = outlet_new(&x->x_obj, 0); x->x_status_outlet = outlet_new(&x->x_obj, 0); - - /* set to the value from the object argument, if that exists */ - if (s != &s_) - x->x_devname = s; return (x); } @@ -320,14 +381,14 @@ void sixaxis_setup(void) sixaxis_class = class_new(gensym("sixaxis"), (t_newmethod)sixaxis_new, (t_method)sixaxis_free, - sizeof(t_sixaxis), 0, A_DEFSYM, 0); + sizeof(t_sixaxis), 0, A_GIMME, 0); /* add inlet datatype methods */ class_addfloat(sixaxis_class,(t_method) sixaxis_float); class_addbang(sixaxis_class,(t_method) sixaxis_read); /* add inlet message methods */ - class_addmethod(sixaxis_class,(t_method) sixaxis_open,gensym("open"),A_DEFFLOAT,0); + class_addmethod(sixaxis_class,(t_method) sixaxis_open,gensym("open"),A_GIMME,0); class_addmethod(sixaxis_class,(t_method) sixaxis_close,gensym("close"),0); class_addmethod(sixaxis_class,(t_method) sixaxis_info,gensym("info"),0); @@ -337,7 +398,13 @@ void sixaxis_setup(void) ps_poll = gensym("poll"); ps_total = gensym("total"); ps_range = gensym("range"); + ps_devname = gensym("devname"); + ps_accelerometer = gensym("accelerometer"); + ps_x = gensym("x"); + ps_y = gensym("y"); + ps_z = gensym("z"); + ps_acceleration = gensym("acceleration"); ps_speed = gensym("speed"); ps_position = gensym("position"); -- cgit v1.2.1 From 590fa42a7ca536666dd4c76a7398b011bbd886e0 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 22 Jul 2008 15:04:33 +0000 Subject: added #define BLUETOOTH_VERSION_USE_CURRENT to get rid of "deprecated" warnings based on this bluetooth-dev post: http://lists.apple.com/archives/Bluetooth-dev/2007/Mar/msg00024.html svn path=/trunk/externals/io/; revision=10205 --- aka.wiiremote/wiiremote.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aka.wiiremote/wiiremote.h b/aka.wiiremote/wiiremote.h index 4a03f09..560e401 100644 --- a/aka.wiiremote/wiiremote.h +++ b/aka.wiiremote/wiiremote.h @@ -2,6 +2,8 @@ // Copyright by Masayuki Akamatsu // Based on "DarwiinRemote" by Hiroaki Kimura +#define BLUETOOTH_VERSION_USE_CURRENT // gets rid of deprecated warnings + #include #include #include -- cgit v1.2.1 From 25dcbfc009a7fbf95a4e2e8788a5cf68d2cdd7b1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 22 Jul 2008 15:23:12 +0000 Subject: first working version, bangs now get udpated data properly, but the various other messages don't work, like [motion $1(, [ir $1(, etc. To get it working, I used CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true), which runs the CFRunLoop until just one event has been processed. svn path=/trunk/externals/io/; revision=10206 --- aka.wiiremote/aka.wiiremote.c | 32 +++++++------------------------- aka.wiiremote/akawiiremote-help.pd | 2 ++ aka.wiiremote/wiiremote.c | 31 ++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/aka.wiiremote/aka.wiiremote.c b/aka.wiiremote/aka.wiiremote.c index 0831f44..5834b63 100644 --- a/aka.wiiremote/aka.wiiremote.c +++ b/aka.wiiremote/aka.wiiremote.c @@ -10,6 +10,7 @@ #ifdef PD #include "m_pd.h" +#include "m_imp.h" #define SETSYM SETSYMBOL #define SETLONG SETFLOAT #define method t_method @@ -48,12 +49,6 @@ typedef struct _akawiiremote void *dataOut; } t_akawiiremote; -#ifdef PD -static IONotificationPortRef gNotifyPort; -static io_iterator_t gAddedIter; -static CFRunLoopRef gRunLoop; -#endif - void akawiiremote_bang(t_akawiiremote *x); void akawiiremote_address(t_akawiiremote *x, t_symbol *s); void akawiiremote_connect(t_akawiiremote *x); @@ -165,7 +160,9 @@ void akawiiremote_bang(t_akawiiremote *x) if (x->wiiremote->device == nil) return; // do nothing - +#ifdef PD + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); +#endif if (x->wiiremote->isExpansionPortAttached && x->wiiremote->isExpansionPortEnabled) { // Classic Controller @@ -544,6 +541,9 @@ void akawiiremote_clock(t_akawiiremote *x) if (x->connected == false && connection == true) // if the device is connected... { +#ifdef PD + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); +#endif wiiremote_getstatus(x->wiiremote); x->connected = true; SETLONG(&status, 1); @@ -595,24 +595,6 @@ void *akawiiremote_new(t_symbol *s, short ac, t_atom *av) first_argument = atom_getsymbolarg(0, ac, av); if(first_argument != &s_) atom_string(av, x->address, MAXPDSTRING-1); - - IOReturn result = kIOReturnSuccess; - mach_port_t masterPort = (mach_port_t) NULL; - result = IOMasterPort (bootstrap_port, &masterPort); - if (kIOReturnSuccess != result) - pd_error(x, "[akawiiremote] IOMasterPort error with bootstrap_port, error %d", result); - else - { - // Create a notification port and add its run loop event source to our run loop - // This is how async notifications get set up. - CFRunLoopSourceRef runLoopSource; - - gNotifyPort = IONotificationPortCreate(masterPort); - runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort); - - gRunLoop = CFRunLoopGetCurrent(); - CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode); - } #else /* Max */ t_akawiiremote *x; diff --git a/aka.wiiremote/akawiiremote-help.pd b/aka.wiiremote/akawiiremote-help.pd index c3ae89a..b2e85ed 100644 --- a/aka.wiiremote/akawiiremote-help.pd +++ b/aka.wiiremote/akawiiremote-help.pd @@ -50,6 +50,7 @@ blinking once its connected; #X obj 632 408 pddp/dsp; #X obj 640 500 osc~ 100; #X obj 303 388 akawiiremote; +#X obj 334 589 print; #X connect 0 0 34 0; #X connect 1 0 34 0; #X connect 2 0 22 0; @@ -63,6 +64,7 @@ blinking once its connected; #X connect 15 0 34 0; #X connect 16 0 34 0; #X connect 19 0 12 0; +#X connect 19 0 35 0; #X connect 19 1 11 0; #X connect 19 2 20 0; #X connect 21 0 34 0; diff --git a/aka.wiiremote/wiiremote.c b/aka.wiiremote/wiiremote.c index 481085e..92efeb0 100644 --- a/aka.wiiremote/wiiremote.c +++ b/aka.wiiremote/wiiremote.c @@ -19,6 +19,7 @@ typedef unsigned char darr[]; Boolean requestUpdates(WiiRemoteRef wiiremote); void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event); +#define DEBUG(x) //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- @@ -73,6 +74,7 @@ void wiiremote_init(WiiRemoteRef wiiremote) Boolean openCChan(WiiRemoteRef wiiremote) { + DEBUG(post("openCChan");); short i; IOReturn ret; @@ -97,6 +99,7 @@ Boolean openCChan(WiiRemoteRef wiiremote) Boolean openIChan(WiiRemoteRef wiiremote) { + DEBUG(post("openCChan");); short i; IOReturn ret; @@ -208,7 +211,7 @@ Boolean readData(WiiRemoteRef wiiremote, unsigned long address, unsigned short l void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) { - post("checkDevice"); + DEBUG(post("checkDevice");); CFStringRef name; CFStringRef address; @@ -234,20 +237,21 @@ void checkDevice(WiiRemoteRef wiiremote, IOBluetoothDeviceRef device) void myFoundFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device) { - post("myFoundFunc"); + DEBUG(post("myFoundFunc");); checkDevice((WiiRemoteRef)refCon, device); } void myUpdatedFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOBluetoothDeviceRef device, uint32_t devicesRemaining) { - post("myUpdatedFunc"); + DEBUG(post("myUpdatedFunc");); checkDevice((WiiRemoteRef)refCon, device); } void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn error, Boolean aborted) { - post("myCompleteFunc"); + IOReturn ret; + DEBUG(post("myCompleteFunc");); if (aborted) return; // called by stop ;) @@ -256,8 +260,15 @@ void myCompleteFunc(void *refCon, IOBluetoothDeviceInquiryRef inquiry, IOReturn wiiremote_stopsearch((WiiRemoteRef)refCon); return; } +/* + ret = IOBluetoothDeviceInquiryStart(((WiiRemoteRef)refCon)->inquiry); + if (ret != kIOReturnSuccess) + { + wiiremote_stopsearch((WiiRemoteRef)refCon); + } +*/ #ifdef PD - // PD doesn't use the Carbon loop, so we have to manually control it + // PD doesn't use a CFRunLoop, so we have to manually control it CFRunLoopStop( CFRunLoopGetCurrent() ); #endif } @@ -274,7 +285,7 @@ Boolean wiiremote_isconnected(WiiRemoteRef wiiremote) Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) { - post("wiiremote_search"); + DEBUG(post("wiiremote_search");); IOReturn ret; if (wiiremote->inquiry != nil) @@ -297,14 +308,14 @@ Boolean wiiremote_search(WiiRemoteRef wiiremote, char *address) return false; } #ifdef PD - CFRunLoopRun(); // PD doesn't use the Carbon loop, so we have to manually control it + // PD doesn't use a CFRunLoop, so we have to manually control it + CFRunLoopRun(); #endif return true; } Boolean wiiremote_stopsearch(WiiRemoteRef wiiremote) { - post("wiiremote_stopsearch"); IOReturn ret; if (wiiremote->inquiry == nil) @@ -703,6 +714,7 @@ void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLe void myDataListener(IOBluetoothL2CAPChannelRef channel, void *dataPointer, UInt16 dataLength, void *refCon) { + DEBUG(post("myDataListener");); WiiRemoteRef wiiremote = (WiiRemoteRef)refCon; unsigned char* dp = (unsigned char*)dataPointer; @@ -738,6 +750,7 @@ void handleButtonReport(WiiRemoteRef wiiremote, unsigned char *dp, size_t dataLe void myEventListener(IOBluetoothL2CAPChannelRef channel, void *refCon, IOBluetoothL2CAPChannelEvent *event) { + DEBUG(post("myEventListener");); if (event->eventType == kIOBluetoothL2CAPChannelEventTypeData) { // In thise case: @@ -846,7 +859,7 @@ Boolean wiiremote_connect(WiiRemoteRef wiiremote) Boolean wiiremote_disconnect(WiiRemoteRef wiiremote) { - short i = 0; + short i; if (wiiremote->cchan) { -- cgit v1.2.1 From ef417b58265bc400d687783c341f84c87b5daa09 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 22 Jul 2008 15:30:52 +0000 Subject: removed CFRunLoopRunInMode() in clock function since it doesn't seem to do anything there svn path=/trunk/externals/io/; revision=10207 --- aka.wiiremote/aka.wiiremote.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/aka.wiiremote/aka.wiiremote.c b/aka.wiiremote/aka.wiiremote.c index 5834b63..7a113b6 100644 --- a/aka.wiiremote/aka.wiiremote.c +++ b/aka.wiiremote/aka.wiiremote.c @@ -538,12 +538,9 @@ void akawiiremote_clock(t_akawiiremote *x) t_atom status; connection = wiiremote_isconnected(x->wiiremote); - + if (x->connected == false && connection == true) // if the device is connected... { -#ifdef PD - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); -#endif wiiremote_getstatus(x->wiiremote); x->connected = true; SETLONG(&status, 1); -- cgit v1.2.1 From 8238e049724286e6a8af96734c71e826c6826006 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 11 Feb 2009 00:50:16 +0000 Subject: first attempt at a Pd port, it compiles without any real warnings, now we just need an xbee to test on! svn path=/trunk/externals/io/; revision=10754 --- xbee/Makefile | 33 ++++ xbee/max2pd.h | 19 ++ xbee/xbee.c | 340 ++++++++++++++++++++++++++++++++++++ xbee/xbee.h | 261 ++++++++++++++++++++++++++++ xbee/xbee_internal.h | 248 +++++++++++++++++++++++++++ xbee/xbee_io.c | 268 +++++++++++++++++++++++++++++ xbee/xbee_io.h | 34 ++++ xbee/xbee_protocol.h | 292 +++++++++++++++++++++++++++++++ xbee/xbee_test-help.pd | 2 + xbee/xbee_test.c | 457 +++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1954 insertions(+) create mode 100644 xbee/Makefile create mode 100644 xbee/max2pd.h create mode 100644 xbee/xbee.c create mode 100644 xbee/xbee.h create mode 100644 xbee/xbee_internal.h create mode 100644 xbee/xbee_io.c create mode 100644 xbee/xbee_io.h create mode 100644 xbee/xbee_protocol.h create mode 100644 xbee/xbee_test-help.pd create mode 100644 xbee/xbee_test.c diff --git a/xbee/Makefile b/xbee/Makefile new file mode 100644 index 0000000..e222c9b --- /dev/null +++ b/xbee/Makefile @@ -0,0 +1,33 @@ +TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') +EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') + +default: + make -C $(EXTERNALS_ROOT) $(TARGET) + +install: + make -C $(EXTERNALS_ROOT) $(TARGET)_install + +clean: + make -C $(EXTERNALS_ROOT) $(TARGET)_clean + +test_locations: + make -C $(EXTERNALS_ROOT) test_locations + +# for emacs +etags: + etags ../../../pd/src/*.h *.[ch] + make etags_`uname -s` + +etags_Darwin: + etags -a \ + /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \ + /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \ + /System/Library/Frameworks/Carbon.framework/Headers/*.h \ + /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[ch] + +etags_Linux: + etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: + etags -a /usr/include/*.h /usr/include/sys/*.h \ + /usr/local/include/*.h /usr/local/include/sys/*.h diff --git a/xbee/max2pd.h b/xbee/max2pd.h new file mode 100644 index 0000000..6f09500 --- /dev/null +++ b/xbee/max2pd.h @@ -0,0 +1,19 @@ +/* + * this header aims to make it easy to port Max objects to Pd + */ + +/* name changes */ +#define SETSYM SETSYMBOL + +/* Pd doesn't have longs */ +#define SETLONG SETFLOAT + +/* allocate memory */ +#define sysmem_newptr(size) getbytes(128) +#define sysmem_freeptr(ptr) freebytes(ptr, 128) + + +#define atom_getlong(atom) atom_getfloatarg(0, 1, atom) +#define atom_getsym(atom) atom_getsymbolarg(0, 1, atom) +#define object_alloc(obj_class) pd_new(obj_class) +#define object_free(obj) pd_free((t_pd*)obj) diff --git a/xbee/xbee.c b/xbee/xbee.c new file mode 100644 index 0000000..c243b5f --- /dev/null +++ b/xbee/xbee.c @@ -0,0 +1,340 @@ +/* + * xbee.c: + * XBee Zigbee module interface functions + * + * (c) 2006-2008 Tymm Twillman + * + */ + +#include +#include /* for memcpy, memset, etc. */ + +#include "xbee_protocol.h" +#include "xbee.h" + + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +/* In case we need to serialize access for transmission; + * reception is made to always come from one XBee module so + * shouldn't need to serialize that. + */ + +#ifndef CONFIG_XBEE_REENTRANT_TX +# define xbee_lock_frame_id(xbee) do {} while(0) +# define xbee_unlock_frame_id(xbee) do {} while(0) +#endif + + +/* Error counters can be added later if desired */ +#define xbee_rx_crc_err(xbee) do {} while(0) +#define xbee_rx_err(xbee) do {} while(0) +#define xbee_rx_dropped(xbee) do {} while(0) +#define xbee_tx_err(xbee) do {} while(0) +#define xbee_tx_dropped(xbee) do {} while(0) + + +# ifdef CONFIG_XBEE_REENTRANT_TX +# error CONFIG_XBEE_REENTRANT_TX requires XBEE_ALLOC to be set! +# endif + +#ifndef ENOMEM +# define ENOMEM 12 +#endif + + + +/* Generate & return next 8-bit frame ID */ +static inline uint8_t xbee_next_frame_id(xbee_t *xbee) +{ + uint8_t frame_id; + + + xbee_lock_frame_id(xbee); + if (++xbee->out.frame_id == 0) + ++xbee->out.frame_id; + frame_id = xbee->out.frame_id; + xbee_unlock_frame_id(xbee); + + return frame_id; +} + + +/* Generate CRC for an XBee packet */ +uint8_t xbee_crc(const xbee_pkt_t *pkt) +{ + uint8_t *pkt_data = ((uint8_t *)pkt) + sizeof(xbee_pkt_hdr_t); + uint16_t i; + uint8_t crc = 0; + + + for (i = 0; i < ntohs(((xbee_pkt_hdr_t *)pkt)->len); i++) + crc += *(pkt_data++); + + return ~crc; +} + + +/* Accept data from an XBee module & build into valid XBEE + * packets + */ +void xbee_in(xbee_t *xbee, const void *buf, uint8_t len) +{ + uint8_t *data = (uint8_t *)buf; + + + while(len) { + switch(xbee->in.bytes_rcvd) { + case 0: + while (*data != XBEE_PKT_START) { + if (!--len) + return; + data++; + } + + xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++; + if (!--len) + return; + + /* Fall thru */ + + case 1: + xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++; + if (!--len) + return; + + /* Fall thru */ + + case 2: + xbee->in.hdr_data[xbee->in.bytes_rcvd++] = *data++; + + /* Got enough to get packet length */ + + xbee->in.bytes_left = ntohs(((xbee_pkt_hdr_t *)xbee->in.hdr_data)->len); + + if (xbee->in.bytes_left > XBEE_MAX_DATA_LEN + || ((xbee->in.packet + = xbee_alloc_pkt_mem(XBEE_RECV, xbee->in.bytes_left + 4)) == NULL) + ) + { + xbee->in.bytes_left = 0; + xbee_rx_err(xbee); + continue; + } + + xbee->in.bytes_left++; /* Extra for crc (alloc_pkt already accounts for it) */ + + memcpy(&(xbee->in.packet->hdr), &(xbee->in.hdr_data), + sizeof(xbee->in.hdr_data)); + + if (!--len) + return; + + /* Fall thru */ + + default: + while (xbee->in.bytes_left--) { + ((uint8_t *)xbee->in.packet)[xbee->in.bytes_rcvd++] = *data++; + if (!--len && xbee->in.bytes_left) + return; + } + } + + if (xbee_crc(xbee->in.packet) + != ((uint8_t *)xbee->in.packet)[xbee->in.bytes_rcvd - 1]) + { + xbee->in.bytes_rcvd = 0; + xbee_rx_crc_err(xbee); + continue; + } + + if (xbee_recv_pkt(xbee, xbee->in.packet, xbee->in.bytes_rcvd)) { + xbee_free_pkt_mem(xbee->in.packet); + xbee_rx_dropped(xbee); + } + + xbee->in.bytes_rcvd = 0; + } +} + + +/* Send a command to an XBee module */ + +int xbee_send_at_cmd(xbee_t *xbee, + const char cmd[], + uint8_t param_len, + const uint8_t params[]) +{ + xbee_at_cmd_pkt_t *pkt; + uint8_t frame_id; + int ret; + + + pkt = (xbee_at_cmd_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, param_len + 8); + if (pkt == NULL) { + xbee_tx_err(); + return -ENOMEM; + } + + xbee_hdr_init(pkt->hdr, param_len + 4); + + pkt->type = XBEE_PKT_TYPE_ATCMD; + + frame_id = xbee_next_frame_id(xbee); + + pkt->frame_id = frame_id; + + pkt->command[0] = cmd[0]; + pkt->command[1] = cmd[1]; + + memcpy(pkt->param, params, param_len); + pkt->param[param_len] = xbee_crc((xbee_pkt_t *)pkt); + + ret = xbee_out(xbee, (xbee_pkt_t *)pkt, + sizeof(xbee_at_cmd_pkt_t) + param_len + 1); + + if (ret >= 0) + return frame_id; + + xbee_free_pkt_mem((xbee_pkt_t *)pkt); + + xbee_tx_err(); + + return ret; +} + + +/* Send a command to a remote XBee module */ + +int xbee_send_remote_at_cmd(xbee_t *xbee, + const char cmd[], + uint8_t param_len, + uint8_t apply, + const uint8_t params[], + const uint8_t addr64[8], + const uint8_t addr16[2]) +{ + xbee_remote_at_cmd_pkt_t *pkt; + uint8_t frame_id; + int ret; + + + pkt = (xbee_remote_at_cmd_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, param_len + 19); + if (pkt == NULL) { + xbee_tx_err(); + return -ENOMEM; + } + + xbee_hdr_init(pkt->hdr, param_len + 15); + + pkt->type = XBEE_PKT_TYPE_REMOTE_ATCMD; + + frame_id = xbee_next_frame_id(xbee); + pkt->frame_id = frame_id; + + memcpy(pkt->dest64, addr64, 8); + memcpy(pkt->dest16, addr16, 2); + + pkt->apply = apply ? 2:0; + + pkt->command[0] = cmd[0]; + pkt->command[1] = cmd[1]; + + memcpy(pkt->param, params, param_len); + pkt->param[param_len] = xbee_crc((xbee_pkt_t *)pkt); + + ret = xbee_out(xbee, (xbee_pkt_t *)pkt, + sizeof(xbee_remote_at_cmd_pkt_t) + param_len + 1); + + if (ret >= 0) + return frame_id; + + xbee_free_pkt_mem((xbee_pkt_t *)pkt); + + xbee_tx_err(); + + return ret; +} + + +/* Send a data packet to another module using its 64-bit unique ID */ +int xbee_send64(xbee_t *xbee, const void *data, uint8_t len, uint8_t opt, const uint8_t addr[8]) +{ + xbee_a64_tx_pkt_t *pkt; + int ret; + uint8_t frame_id; + + + pkt = (xbee_a64_tx_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, len + 15); + if (pkt == NULL) { + xbee_tx_err(xbee); + return -ENOMEM; + } + + xbee_hdr_init(pkt->hdr, len + 11); + + pkt->type = XBEE_PKT_TYPE_TX64; + memcpy(pkt->dest, addr, 8); + pkt->opt = opt; + frame_id = xbee_next_frame_id(xbee); + pkt->frame_id = frame_id; + memcpy(pkt->data, data, len); + pkt->data[len] = xbee_crc((xbee_pkt_t *)pkt); + + ret = xbee_out(xbee, (xbee_pkt_t *)pkt, len + sizeof(xbee_a64_tx_pkt_t) + 1); + + if (ret >= 0) + return frame_id; + + xbee_tx_err(xbee); + + xbee_free_pkt_mem((xbee_pkt_t *)pkt); + + return ret; +} + + +/* Send a data packet to another module using its 16-bit ID */ +int xbee_send16(xbee_t *xbee, const void *data, uint8_t len, uint8_t opt, const uint8_t addr[2]) +{ + xbee_a16_tx_pkt_t *pkt; + uint8_t frame_id; + int ret; + + + pkt = (xbee_a16_tx_pkt_t *)xbee_alloc_pkt_mem(XBEE_XMIT, len + 9); + if (pkt == NULL) { + xbee_tx_err(xbee); + return -ENOMEM; + } + + xbee_hdr_init(pkt->hdr, len + 5); + + pkt->type = XBEE_PKT_TYPE_TX16; + memcpy(pkt->dest, addr, 2); + pkt->opt = opt; + frame_id = xbee_next_frame_id(xbee); + pkt->frame_id = frame_id; + memcpy(pkt->data, (uint8_t *)data, len); + pkt->data[len] = xbee_crc((xbee_pkt_t *)pkt); + + ret = xbee_out(xbee, (xbee_pkt_t *)pkt, len + sizeof(xbee_a16_tx_pkt_t) + 1); + + if (ret >= 0) + return frame_id; + + xbee_tx_err(); + + xbee_free_pkt_mem((xbee_pkt_t *)pkt); + + return ret; +} + + +/* Initialize this package */ +void xbee_init(xbee_t *xbee) +{ + memset(xbee, 0, sizeof(xbee_t)); +} diff --git a/xbee/xbee.h b/xbee/xbee.h new file mode 100644 index 0000000..a40487e --- /dev/null +++ b/xbee/xbee.h @@ -0,0 +1,261 @@ +/* + * xbee.h: + * Maxstream XBee module Interface Header + * + * (c) 2006-2008 Tymm Twillman + * + * + * NOTE: This doesn't touch hardware; it's up to developers to link in functions + * that handle hardware communication. + * + * DEVELOPERS: Pieces you need to implement (see prototypes, below): + * xbee_alloc_pkt_mem (can just return static data) + * xbee_free_pkt_mem (can do nothing if not dynamic) + * + * xbee_out + * xbee_recv_pkt + * + * What you need to call from wherever you read data from UART, etc: + * xbee_in + * + * Incoming data from UART, etc. should be passed to xbee_in; it will + * be built into well-formed packets and passed to xbee_recv_pkt + * for further processing. + * + * Outgoing data will be passed to xbee_out to be passed off to + * the XBee hardware. + * + * + */ + +#ifndef XBEE_H +#define XBEE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/*---------------------------------------------------------------------------- + Definitions for commands the XBee recognizes + ----------------------------------------------------------------------------*/ + +/* Basic communication parameters/values */ + +#define XBEE_CMD_CHANNEL "CH" +#define XBEE_CMD_PAN_ID "ID" +#define XBEE_CMD_DEST_ADDR64_HI "DH" +#define XBEE_CMD_DEST_ADDR64_LO "DL" +#define XBEE_CMD_SRC_ADDR16 "MY" +#define XBEE_CMD_SER_HI "SH" +#define XBEE_CMD_SER_LO "SL" +#define XBEE_CMD_RAND_DLY_SLOTS "RN" +#define XBEE_CMD_MAC_MODE "MM" +#define XBEE_CMD_COORD_ENA "CE" +#define XBEE_CMD_SCAN "SC" +#define XBEE_CMD_SCAN_DURATION "SD" +#define XBEE_CMD_ASSOC_END "A1" +#define XBEE_CMD_ASSOC_COORD "A2" +#define XBEE_CMD_ASSOC_STATUS "AI" +#define XBEE_CMD_RSSI "DB" + +/* Transceiver Control */ + +#define XBEE_CMD_PWR_LEVEL "PL" +#define XBEE_CMD_CCA_THRESH "CA" + +/* Sleep Parameters */ + +#define XBEE_CMD_SLEEP_MODE "SM" +#define XBEE_CMD_SLEEP_TIMEOUT "ST" +#define XBEE_CMD_SLEEP_PERIOD "SP" +#define XBEE_CMD_SLEEP_PERIOD_DISASSOC "DP" + +/* Interface parameters */ + +#define XBEE_CMD_DATA_RATE "BD" +#define XBEE_CMD_PACKETIZATION_TIMEOUT "RO" +#define XBEE_CMD_DIO7_CONFIG "D7" +#define XBEE_CMD_DIO6_CONFIG "D6" +#define XBEE_CMD_DIO5_CONFIG "D5" +#define XBEE_CMD_PWM0_CONFIG "PO" +#define XBEE_CMD_API_ENA "AP" +#define XBEE_CMD_PULLUP_ENA "PR" + +/* Version Info */ + +#define XBEE_CMD_VERS_FIRMWARE "VR" +#define XBEE_CMD_VERS_HARDWARE "HV" +#define XBEE_CMD_VERS_FIRM_VERBOSE "VL" + +/* Received Signal Strength */ + +#define XBEE_CMD_RSSI_PWM_TIMER "RP" +#define XBEE_CMD_RSS "DB" + +/* Error counters */ + +#define XBEE_CMD_CCA_FAILS "EC" +#define XBEE_CMD_ACK_FAILS "EA" + +/* AT Command Params */ + +#define XBEE_CMD_AT_MODE_TIMEOUT "CT" +#define XBEE_CMD_AT_GUARD_TIME "GT" +#define XBEE_CMD_AT_CMD_CHAR "CC" +#define XBEE_CMD_AT_EXIT "CN" + +/* XBEE specific routing */ + +#define XBEE_CMD_NODE_FIND_DEST "DN" +#define XBEE_CMD_NODE_DISCOVER "ND" +#define XBEE_CMD_NODE_ID "NI" +#define XBEE_CMD_ACTIVE_SCAN "AS" +#define XBEE_CMD_FORCE_DISASSOC "DA" +#define XBEE_CMD_ENERGY_SCAN "ED" +#define XBEE_CMD_FORCE_POLL "FP" + +/* Misc */ + +#define XBEE_CMD_WRITE_PARAMS "WR" +#define XBEE_CMD_RESET_SOFT "FR" +#define XBEE_CMD_APPLY_CHANGES "AC" +#define XBEE_CMD_RESTORE_DEFAULTS "RE" + + +/*---------------------------------------------------------------------------- + Structures usefull for communicating with the XBee in API mode + ----------------------------------------------------------------------------*/ + +/* Packets are wrapped with a start & length */ +typedef struct { + uint8_t start; /* 0x7e */ + uint16_t len; +} __attribute__ ((__packed__)) xbee_pkt_hdr_t; + + +/* Packets can be broken up into headers, a packet type, a number of data + * bytes and a crc (at the end of the data) + */ +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t data[0]; + /* uint8_t crc; */ +} __attribute__ ((__packed__)) xbee_pkt_t; + + +/* Context for tracking current state of communication with an + * XBee module + */ +typedef struct { + struct { + uint8_t bytes_left; + uint8_t bytes_rcvd; + xbee_pkt_t *packet; + uint8_t hdr_data[sizeof(xbee_pkt_hdr_t)]; + } in; + struct { + uint8_t frame_id; + } out; + void *user_context; // yours to pass data around with +} __attribute__ ((__packed__)) xbee_t; + +/* This is used for keeping track of your data as things get passed around + * through the xbee interface + */ +#define xbee_user_context(xbee) ((xbee).user_context) + +/*---------------------------------------------------------------------------- + Internal calls + ----------------------------------------------------------------------------*/ + +/* Calculate CRC on an xbee packet */ +uint8_t xbee_crc(const xbee_pkt_t *pkt); + + +/*---------------------------------------------------------------------------- + Generally all the functions you need to call + ----------------------------------------------------------------------------*/ + +/* Receive data, calling xbee_recv_pkt on each packet when it's done + * assembling; this should be called with raw data from UART, etc. + * as it comes in. *** YOU NEED TO CALL THIS *** + */ +void xbee_in(xbee_t *xbee, const void *data, uint8_t len); + +/* Send a packet with a 64-bit destination address (Series 1) */ +int xbee_send64(xbee_t *xbee, + const void *data, + uint8_t len, + uint8_t opt, + const uint8_t addr[8]); + +/* Send a packet with a 16-bit destination address (Series 1) */ +int xbee_send16(xbee_t *xbee, + const void *data, + uint8_t len, + uint8_t opt, + const uint8_t addr[2]); + +/* Send a command to the xbee modem */ +int xbee_send_at_cmd(xbee_t *xbee, + const char cmd[], + uint8_t param_len, + const uint8_t *params); + +/* Send a command to a remote xbee modem (Series 2 & Newer Series 1 only) */ +int xbee_send_remote_at_cmd(xbee_t *xbee, + const char cmd[], + uint8_t param_len, + uint8_t apply, + const uint8_t params[], + const uint8_t addr64[8], + const uint8_t addr16[2]); + +/* Initialize the XBee interface */ +void xbee_init(xbee_t *xbee); + +/*---------------------------------------------------------------------------- + MUST be provided externally to this package + ----------------------------------------------------------------------------*/ + +/* Queue a packet for transmission (needs to queue packet to be sent to XBEE + * module; e.g. copy the packet to a UART buffer). + * On error, -1 should be returned and the packet should NOT be freed. + * On success, 0 should be returned; if XBEE_ALLOC is set, this function or + * someone downstream is responsible for freeing it -- the packet has been + * handed off. This is to minimize copying of data. + */ +int xbee_out(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len); + +/* Handle an incoming packet; the packet will be fully formed and verified + * for proper construction before being passed off to this function. This + * function should dig into the packet & process based on its contents. + */ +int xbee_recv_pkt(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len); + + +/*---------------------------------------------------------------------------- + Must be provided externally only if using dynamic memory (which allows more + than one packet to be queued at a time) + ----------------------------------------------------------------------------*/ + +/* Return a buffer for an xbee packet; at least bytes need to be allocated + * + * Direction since we may want to have different allocations mechanisms/etc + * for xmit vs recv. + */ +void *xbee_alloc_pkt_mem(uint8_t direction, uint8_t len); + +/* Free up an allocated packet */ +void xbee_free_pkt_mem(xbee_pkt_t *pkt); + + +#ifdef __cplusplus +}; +#endif + +#endif /* #ifndef XBEE_H ... */ diff --git a/xbee/xbee_internal.h b/xbee/xbee_internal.h new file mode 100644 index 0000000..83273d4 --- /dev/null +++ b/xbee/xbee_internal.h @@ -0,0 +1,248 @@ +#ifndef XBEE_INTERNAL_H +#define XBEE_INTERNAL_H + +#ifdef AVR +# define __LITTLE_ENDIAN 1234 +# define BYTE_ORDER LITTLE_ENDIAN +#elif defined(ARM) +# include +#else +# include +#endif + +#include + +#include "xbee.h" + +#if !defined(ntohs) && (BYTE_ORDER == LITTLE_ENDIAN) +# define ntohs(n) ((((short)(n)) & 0xff00) >> 8 | (((short)(n)) & 0xff) << 8) +# define htons(n) ntohs(n) +#elif !defined(ntohs) +# define ntohs(n) ((short)(n)) +# define htons(n) ntohs(n) +#endif + +#if !defined(ntohl) && (BYTE_ORDER == LITTLE_ENDIAN) +# define ntohl(x) ((((x)&0xff000000)>>24) \ + |(((x)&0x00ff0000)>>8) \ + |(((x)&0x0000ff00)<<8) \ + |(((x)&0x000000ff)<<24)) +# define htonl(n) ntohl(n) +#elif !defined(ntohl) +# define ntohl(n) ((long)(n)) +# define htonl(n) ntohs(n) +#endif + +/* p2p CE=0 (end devices) A1=0 (no end dev assoc) same ID/CH + * coordinator: CE=1, A2=n (coordinator assoc) + * SP= sleep perd ST= time betw sleep (should be same on + * coord/noncoord) + * assoc - coord'd only; comm between modules thru coord'r + * PAN's - need coordinator. A1 allows totally dynamic assoc + */ + + +/* --- General XBee Definitions --- */ + +/* "Start of packet" byte; always sent as the first + * byte of each packet + */ +#define XBEE_PKT_START 0x7e + + +/* Maximum packet size; datasheet basically says 100 payload bytes max */ +#define XBEE_MAX_DATA_LEN 128 + + +/* --- Bits in packets --- */ + +/* Communication status bits */ + +#define XBEE_STATUS_HW_RESET 0x01 +#define XBEE_STATUS_WD_RESET 0x02 +#define XBEE_STATUS_ASSOC 0x04 +#define XBEE_STATUS_DISASSOC 0x08 +#define XBEE_STATUS_SYNC_LOST 0x10 +#define XBEE_STATUS_COORD_REALIGN 0x20 +#define XBEE_STATUS_COORD_RESET 0x40 + +/* Command status bits */ + +#define XBEE_CMDSTATUS_OK 0 +#define XBEE_CMDSTATUS_ERR 1 + +/* Transmit options */ + +#define XBEE_TX_FLAG_NO_ACK 0x01 +#define XBEE_TX_FLAG_SEND_BCAST_PAN_ID 0x04 + +/* Transmit status bits */ + +#define XBEE_TXSTATUS_SUCCESS 0x00 +#define XBEE_TXSTATUS_NO_ACK 0x01 +#define XBEE_TXSTATUS_CCA_FAIL 0x02 +#define XBEE_TXSTATUS_PURGES 0x03 + +/* Received options */ + +#define XBEE_RX_FLAG_ADDR_BCAST 0x02 +#define XBEE_RX_FLAG_PAN_BCAST 0x04 + + +/* --- Definitions & macros for library use --- */ + +/* For tracking memory allocations */ +#define XBEE_RECV 0x00 +#define XBEE_XMIT 0x01 + +/* Initialize an XBee header */ +#define xbee_hdr_init(hdr, data_len) \ + ((hdr).start = 0x7e, (hdr).len = htons(data_len)) + +/* To get the length of the data portion of a received packet */ + +#define xbee_recv_a64_data_len(pkt) (ntohs(pkt->hdr.len) - 11) +#define xbee_recv_a16_data_len(pkt) (ntohs(pkt->hdr.len) - 5) +#define xbee_cmd_resp_param_len(pkt) (ntohs(pkt->hdr.len) - 5) + +#ifdef XBEE_ALLOC +# define xbee_alloc_pkt(dir, data_len) \ + (xbee_pkt_t *)xbee_alloc_buf((dir), (data_len) + sizeof(xbee_pkt_hdr_t) + 1) +#endif + +/* Types of packets from/to xbee modules; these are used + * in the "type" field of each packet structure + */ + +typedef enum { + XBEE_PKT_TYPE_TX64 = 0x00, + XBEE_PKT_TYPE_TX16 = 0x01, + XBEE_PKT_TYPE_ATCMD = 0x08, + XBEE_PKT_TYPE_QATCMD = 0x09, /* wait til an immed param or apply cmd */ + XBEE_PKT_TYPE_REMOTE_ATCMD = 0x17, + XBEE_PKT_TYPE_RX64 = 0x80, + XBEE_PKT_TYPE_RX16 = 0x81, + XBEE_PKT_TYPE_RX64_IO = 0x82, + XBEE_PKT_TYPE_RX16_IO = 0x83, + XBEE_PKT_TYPE_ATCMD_RESP = 0x88, + XBEE_PKT_TYPE_TX_STATUS = 0x89, + XBEE_PKT_TYPE_MODEM_STATUS= 0x8a, +} xbee_pkt_type_t; + + +/* --- Packet layouts --- */ + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t command[2]; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_at_cmd_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest64[8]; + uint8_t dest16[2]; + uint8_t apply; + uint8_t command[2]; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_remote_at_cmd_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest[8]; + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a64_tx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest[2]; + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a16_tx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t status; +} __attribute__ ((__packed__)) xbee_tx_status_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t status; +} __attribute__ ((__packed__)) xbee_modem_status_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t command[2]; + uint8_t status; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_cmd_resp_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[8]; + uint8_t rssi; /* signal strength */ + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a64_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[2]; + uint8_t rssi; + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a16_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[8]; + uint8_t rssi; /* signal strength */ + uint8_t opt; + uint8_t num_samples; + uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */ + uint16_t data[0]; /* First sample digital if any digital chan active + rest are 16-bit analog rdgs */ +} __attribute__ ((__packed__)) xbee_io_a64_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[2]; + uint8_t rssi; + uint8_t opt; + uint8_t num_samples; + uint8_t achan; + uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */ + uint16_t data[0]; /* First sample digital if any digital chan active + rest are 16-bit analog rdgs */ +} __attribute__ ((__packed__)) xbee_io_a16_rx_pkt_t; + +#endif /* #ifndef XBEE_INTERNAL_H ... */ + diff --git a/xbee/xbee_io.c b/xbee/xbee_io.c new file mode 100644 index 0000000..d3fe323 --- /dev/null +++ b/xbee/xbee_io.c @@ -0,0 +1,268 @@ +/* + * xbee_io.c + * xbee_test + * + * Created by Tymm on 11/20/08. + * Copyright 2008 __MyCompanyName__. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +#ifdef PD +#include "m_pd.h" +#include "max2pd.h" +#else +#include "ext.h" +#endif /* PD */ + +#include "xbee.h" +#include "xbee_io.h" + + +#ifndef MIN +# define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + + +void xbee_io_read(xbee_t *xbee) +{ + int r; + char data[128]; + xbee_io_context_t *ctx = xbee_user_context(*xbee); + int xbee_fd = ctx->fd; + + + r = read(xbee_fd, data, sizeof(data)); + if (r <= 0) { + return; + } + + xbee_in(xbee, data, r); +} + + +void xbee_io_write(xbee_t *xbee) +{ + int r; + int max_bytes_to_write; + xbee_io_context_t *ctx = xbee_user_context(*xbee); + int xbee_fd = ctx->fd; + int tmp_start = ctx->out_buffer_start; + + + if (tmp_start != ctx->out_buffer_end) { + max_bytes_to_write = (ctx->out_buffer_end + XBEE_IO_BUFSIZ - ctx->out_buffer_start) % XBEE_IO_BUFSIZ; + + //for (r = 0; r < MIN(max_bytes_to_write, XBEE_IO_BUFSIZ - tmp_start); r++) { + // post("%02x", (unsigned char)ctx->out_buffer[tmp_start + r]); + //} + + r = write(xbee_fd, (char *)(ctx->out_buffer + tmp_start), MIN(max_bytes_to_write, XBEE_IO_BUFSIZ - tmp_start)); + + if (r < 0) { + return; + } + + tmp_start += r; + tmp_start %= XBEE_IO_BUFSIZ; + + ctx->out_buffer_start = tmp_start; + + if (tmp_start == 0) { + max_bytes_to_write -= r; + + r = write(xbee_fd, (char *)(ctx->out_buffer), max_bytes_to_write); + + if (r < 0) { + return; + } + + tmp_start += r; + tmp_start %= XBEE_IO_BUFSIZ; + } + + ctx->out_buffer_start = tmp_start; + } +} + + +int xbee_put_data(xbee_io_context_t *ctx, char *data, int len) +{ + int byte_count = 0; + int max_bytes; + int tmp_end = ctx->out_buffer_end; + + + max_bytes = MIN((ctx->out_buffer_start + XBEE_IO_BUFSIZ - tmp_end - 1) % XBEE_IO_BUFSIZ, len); + byte_count = MIN(max_bytes, XBEE_IO_BUFSIZ - tmp_end); + + memcpy((char *)(ctx->out_buffer + tmp_end), data, byte_count); + + if (byte_count != max_bytes) { + memcpy((char *)(ctx->out_buffer), data + byte_count, max_bytes - byte_count); + } + + tmp_end += max_bytes; + tmp_end %= XBEE_IO_BUFSIZ; + ctx->out_buffer_end = tmp_end; + + return max_bytes; +} + + +void *xbee_io_loop(void *param) +{ + int xbee_fd; + fd_set r_fds, w_fds; + int nfds = 0; + struct timeval timeout; + struct timeval timeout_orig = { .tv_sec = 1, .tv_usec = 0 }; + xbee_t *xbee = param; + xbee_io_context_t *ctx = xbee_user_context(*xbee); + int notif_fd; + int maxfd; + + + xbee_fd = ctx->fd; + notif_fd = ctx->pipe_fds[0]; + + FD_ZERO(&r_fds); + FD_ZERO(&w_fds); + + while(1) { + if (ctx->io_done) { + break; + } + + nfds = 0; + + FD_SET(notif_fd, &r_fds); + maxfd = notif_fd; + + FD_SET(xbee_fd, &r_fds); + if (xbee_fd > maxfd) + maxfd = xbee_fd; + + FD_CLR(xbee_fd, &w_fds); + if (ctx->out_buffer_start != ctx->out_buffer_end) { + FD_SET(xbee_fd, &w_fds); + } + + // For Linux compat + timeout = timeout_orig; + + nfds = select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); + + if (nfds >= 1) { + if (FD_ISSET(notif_fd, &r_fds)) { + // We've been notified that there's data to be read, or need to exit + char blah; + read(notif_fd, &blah, 1); + } + + if (FD_ISSET(xbee_fd, &r_fds)) { + xbee_io_read(xbee); + } + + if (FD_ISSET(xbee_fd, &w_fds)) { + xbee_io_write(xbee); + } + } + } + + ctx->io_running = 0; + + return NULL; +} + + +int xbee_kill_io_thread(xbee_t *xbee) +{ + xbee_io_context_t *ctx; + void *val; + + + ctx = xbee_user_context(*xbee); + + if (ctx != NULL) { + if (ctx->io_running) { + ctx->io_done = 1; + + write(ctx->pipe_fds[1], "!", 1); + + if (pthread_join(ctx->io_thread, &val) < 0) { + return -1; + } + + post("xbee_test: xbee io thread stopped."); + } + } + + return 0; +} + + +int xbee_new_io_thread(xbee_t *xbee) +{ + xbee_io_context_t *ctx = xbee_user_context(*xbee); + int r; + + + if (!ctx->io_running) { + ctx->io_running = 1; + + r = pthread_create(&ctx->io_thread, NULL, &xbee_io_loop, (void *)xbee); + if (r < 0) { + ctx->io_running = 0; + return -1; + } + + post("xbee_test: xbee io thread started."); + } + + return 0; +} + + +int xbee_out(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len) +{ + xbee_io_context_t *ctx = xbee_user_context(*xbee); + int r; + + + r = xbee_put_data(ctx, (void *)pkt, len); + xbee_free_pkt_mem(pkt); + + return r; +} + + +int xbee_recv_pkt(xbee_t *xbee, xbee_pkt_t *pkt, uint8_t len) +{ + //int i; + + + //for (i = 0; i < len; i++) { + // post("GOT %02x", ((unsigned char *)pkt)[i]); + //} + + xbee_free_pkt_mem(pkt); + return 0; +} + + +void *xbee_alloc_pkt_mem(uint8_t direction, uint8_t len) +{ + return sysmem_newptr(128); +} + + +void xbee_free_pkt_mem(xbee_pkt_t *pkt) +{ + sysmem_freeptr(pkt); +} diff --git a/xbee/xbee_io.h b/xbee/xbee_io.h new file mode 100644 index 0000000..a7f5363 --- /dev/null +++ b/xbee/xbee_io.h @@ -0,0 +1,34 @@ +/* + * xbee_io.h + * xbee_test + * + * Created by Tymm on 11/24/08. + * Copyright 2008 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef XBEE_IO_H +#define XBEE_IO_H + +#include + +#include "xbee.h" + + +#define XBEE_IO_BUFSIZ 16384 + +typedef struct { + int fd; + int pipe_fds[2]; // For indicating new data ready + pthread_t io_thread; + int io_done; + int io_running; + int out_buffer_start; + int out_buffer_end; + char out_buffer[XBEE_IO_BUFSIZ]; +} xbee_io_context_t; + +int xbee_new_io_thread(xbee_t *xbee); +int xbee_kill_io_thread(xbee_t *xbee); + +#endif /* #ifndef XBEE_IO_H ... */ diff --git a/xbee/xbee_protocol.h b/xbee/xbee_protocol.h new file mode 100644 index 0000000..bb80a60 --- /dev/null +++ b/xbee/xbee_protocol.h @@ -0,0 +1,292 @@ +#ifndef XBEE_PROTOCOL_H +#define XBEE_PROTOCOL_H + +#ifdef AVR +# define __LITTLE_ENDIAN 1234 +# define BYTE_ORDER LITTLE_ENDIAN +#elif defined(ARM) +# include +#else +# include +#endif + +#include + +#include "xbee.h" + +#if !defined(ntohs) && (BYTE_ORDER == LITTLE_ENDIAN) +# define ntohs(n) ((((short)(n)) & 0xff00) >> 8 | (((short)(n)) & 0xff) << 8) +# define htons(n) ntohs(n) +#elif !defined(ntohs) +# define ntohs(n) ((short)(n)) +# define htons(n) ntohs(n) +#endif + +#if !defined(ntohl) && (BYTE_ORDER == LITTLE_ENDIAN) +# define ntohl(x) ((((x)&0xff000000)>>24) \ + |(((x)&0x00ff0000)>>8) \ + |(((x)&0x0000ff00)<<8) \ + |(((x)&0x000000ff)<<24)) +# define htonl(n) ntohl(n) +#elif !defined(ntohl) +# define ntohl(n) ((long)(n)) +# define htonl(n) ntohs(n) +#endif + +/* p2p CE=0 (end devices) A1=0 (no end dev assoc) same ID/CH + * coordinator: CE=1, A2=n (coordinator assoc) + * SP= sleep perd ST= time betw sleep (should be same on + * coord/noncoord) + * assoc - coord'd only; comm between modules thru coord'r + * PAN's - need coordinator. A1 allows totally dynamic assoc + */ + + +/* --- General XBee Definitions --- */ + +/* "Start of packet" byte; always sent as the first + * byte of each packet + */ +#define XBEE_PKT_START 0x7e + + +/* Maximum packet size; datasheet basically says 100 payload bytes max */ +#define XBEE_MAX_DATA_LEN 128 + + +/* --- Bits in packets --- */ + +/* Communication status bits */ + +#define XBEE_STATUS_HW_RESET 0x01 +#define XBEE_STATUS_WD_RESET 0x02 +#define XBEE_STATUS_ASSOC 0x04 +#define XBEE_STATUS_DISASSOC 0x08 +#define XBEE_STATUS_SYNC_LOST 0x10 +#define XBEE_STATUS_COORD_REALIGN 0x20 +#define XBEE_STATUS_COORD_RESET 0x40 + +/* Command status bits */ + +#define XBEE_CMDSTATUS_OK 0 +#define XBEE_CMDSTATUS_ERR 1 + +/* Transmit options */ + +#define XBEE_TX_FLAG_NO_ACK 0x01 +#define XBEE_TX_FLAG_SEND_BCAST_PAN_ID 0x04 + +/* Transmit status bits */ + +#define XBEE_TXSTATUS_SUCCESS 0x00 +#define XBEE_TXSTATUS_NO_ACK 0x01 +#define XBEE_TXSTATUS_CCA_FAIL 0x02 +#define XBEE_TXSTATUS_PURGES 0x03 + +/* Received options */ + +#define XBEE_RX_FLAG_ADDR_BCAST 0x02 +#define XBEE_RX_FLAG_PAN_BCAST 0x04 + + +/* --- Definitions & macros for library use --- */ + +/* For tracking memory allocations */ +#define XBEE_RECV 0x00 +#define XBEE_XMIT 0x01 + +/* Initialize an XBee header */ +#define xbee_hdr_init(hdr, data_len) \ + ((hdr).start = 0x7e, (hdr).len = htons(data_len)) + +/* To get the length of the data portion of a received packet */ + +#define xbee_recv_a64_data_len(pkt) (ntohs(pkt->hdr.len) - 11) +#define xbee_recv_a16_data_len(pkt) (ntohs(pkt->hdr.len) - 5) +#define xbee_cmd_resp_param_len(pkt) (ntohs(pkt->hdr.len) - 5) + +#ifdef XBEE_ALLOC +# define xbee_alloc_pkt(dir, data_len) \ + (xbee_pkt_t *)xbee_alloc_buf((dir), (data_len) + sizeof(xbee_pkt_hdr_t) + 1) +#endif + +/* Types of packets from/to xbee modules; these are used + * in the "type" field of each packet structure + */ + +typedef enum { + XBEE_PKT_TYPE_TX64 = 0x00, + XBEE_PKT_TYPE_TX16 = 0x01, + XBEE_PKT_TYPE_ATCMD = 0x08, + XBEE_PKT_TYPE_QATCMD = 0x09, /* wait til an immed param or apply cmd */ + XBEE_PKT_TYPE_ZB_TX_REQ = 0x10, + XBEE_PKT_TYPE_ZB_CMD_FRAME = 0x11, /* Not yet impl */ + XBEE_PKT_TYPE_REMOTE_ATCMD = 0x17, + XBEE_PKT_TYPE_RX64 = 0x80, + XBEE_PKT_TYPE_RX16 = 0x81, + XBEE_PKT_TYPE_RX64_IO = 0x82, + XBEE_PKT_TYPE_RX16_IO = 0x83, + XBEE_PKT_TYPE_ATCMD_RESP = 0x88, + XBEE_PKT_TYPE_TX_STATUS = 0x89, + XBEE_PKT_TYPE_MODEM_STATUS = 0x8a, + XBEE_PKT_TYPE_ZB_TX_STATUS = 0x8b, /* Not yet impl */ + XBEE_PKT_TYPE_ADV_MODEM_STATUS = 0x8c, /* Not yet impl */ + XBEE_PKT_TYPE_ZB_RX = 0x90, + XBEE_PKT_TYPE_ZB_RX_IO = 0x92, /* Not yet impl */ + XBEE_PKT_TYPE_RX_SENSOR = 0x94, /* Not yet impl */ + XBEE_PKT_TYPE_NODE_IDENT = 0x95, /* Not yet impl */ + XBEE_PKT_TYPE_REMOTE_ATCMD_RESP = 0x97, +} xbee_pkt_type_t; + + +/* --- Packet layouts --- */ + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t command[2]; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_at_cmd_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest64[8]; + uint8_t dest16[2]; + uint8_t apply; + uint8_t command[2]; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_remote_at_cmd_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest[8]; + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a64_tx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest[2]; + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a16_tx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t status; +} __attribute__ ((__packed__)) xbee_tx_status_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t status; +} __attribute__ ((__packed__)) xbee_modem_status_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t command[2]; + uint8_t status; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_cmd_resp_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t src64[8]; + uint8_t src16[2]; + uint8_t command[2]; + uint8_t status; + uint8_t param[0]; +} __attribute__ ((__packed__)) xbee_remote_cmd_resp_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[8]; + uint8_t rssi; /* signal strength */ + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a64_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[2]; + uint8_t rssi; + uint8_t opt; + uint8_t data[0]; +} __attribute__ ((__packed__)) xbee_a16_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[8]; + uint8_t rssi; /* signal strength */ + uint8_t opt; + uint8_t num_samples; + uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */ + uint16_t data[0]; /* First sample digital if any digital chan active + rest are 16-bit analog rdgs */ +} __attribute__ ((__packed__)) xbee_io_a64_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src[2]; + uint8_t rssi; + uint8_t opt; + uint8_t num_samples; + uint8_t achan; + uint16_t ch_ind; /* bits 14-9: a5-a0 bits 8-0: d8-d0 active */ + uint16_t data[0]; /* First sample digital if any digital chan active + rest are 16-bit analog rdgs */ +} __attribute__ ((__packed__)) xbee_io_a16_rx_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t frame_id; + uint8_t dest64[8]; + uint8_t dest16[2]; + uint8_t radius; + uint8_t opt; /* Multicast = bit 3 */ + uint8_t data[0]; /* Up to 72 bytes/pkt */ +} __attribute__ ((__packed__)) xbee_zb_tx_req_pkt_t; + + +typedef struct { + xbee_pkt_hdr_t hdr; + uint8_t type; + uint8_t src64[8]; + uint8_t src16[2]; + uint8_t opt; + uint8_t data[0]; /* Up to 72 bytes/pkt */ +} __attribute__ ((__packed__)) xbee_zb_rx_pkt_t; + + +#endif /* #ifndef XBEE_PROTOCOL_H ... */ + diff --git a/xbee/xbee_test-help.pd b/xbee/xbee_test-help.pd new file mode 100644 index 0000000..f00c516 --- /dev/null +++ b/xbee/xbee_test-help.pd @@ -0,0 +1,2 @@ +#N canvas 191 22 450 300 10; +#X obj 157 89 xbee_test /dev/tty.Bluetooth-Modem; diff --git a/xbee/xbee_test.c b/xbee/xbee_test.c new file mode 100644 index 0000000..7408b57 --- /dev/null +++ b/xbee/xbee_test.c @@ -0,0 +1,457 @@ +/** + @file + xbee_test - test xbee communication + + @ingroup examples +*/ + +#include +#include +#include +#include +#include +#include + +#ifdef PD +#include "m_pd.h" +#include "max2pd.h" +#else +#include "ext.h" // standard Max include, always required +#include "ext_obex.h" // required for new style Max object + +# ifdef MAC_VERSION +# include "ext_strings.h" +# endif +#endif /* PD */ + +#include "xbee.h" +#include "xbee_io.h" + +////////////////////////// object struct +typedef struct _xbee_test +{ + t_object a_ob; // the object itself (must be first) + long baud; + uint8_t dest_addr64[8]; + uint8_t dest_addr16[2]; + xbee_t *xbee; +} t_xbee_test; + + +///////////////////////// function prototypes +//// standard set +void *xbee_test_new(t_symbol *s, long argc, t_atom *argv); +void xbee_test_free(t_xbee_test *x); +void xbee_test_assist(t_xbee_test *x, void *b, long m, long a, char *s); +//// additional methods +void xbee_test_bang(t_xbee_test *x); // incoming bang message +void xbee_test_close(t_xbee_test *x); +int xbee_test_open_device(t_xbee_test *x, t_symbol *s); +void xbee_test_dest64(t_xbee_test *x, t_symbol *s); +void xbee_test_dest16(t_xbee_test *x, t_symbol *s); +static void xbee_test_on(t_xbee_test *x, long dpin); +static void xbee_test_off(t_xbee_test *x, long dpin); + + +//////////////////////// global class pointer variable +void *xbee_test_class; + + +static int set_baud(int fd, int baud_rate) +{ + struct termios termios; + speed_t speed; + + + switch(baud_rate) { + case 50: + speed = B50; + break; + case 75: + speed = B75; + break; + case 110: + speed = B110; + break; + case 300: + speed = B300; + break; + case 600: + speed = B600; + break; + case 1200: + speed = B1200; + break; + case 2400: + speed = B2400; + break; + case 4800: + speed = B4800; + break; + case 9600: + speed = B9600; + break; + case 19200: + speed = B19200; + break; + case 38400: + speed = B38400; + break; + case 57600: + speed = B57600; + break; + case 115200: + speed = B115200; + break; + case 230400: + speed = B230400; + break; +#ifdef B256000 + case 256000: + speed = B256000; + break; +#endif + default: + return -1; + } + + if (tcgetattr(fd, &termios) < 0) { + error("xbee_test: tcgetattr failed (%d)", errno); + return -1; + } + + termios.c_cflag |= CLOCAL; + + if (cfsetispeed(&termios, speed) < 0) { + error("xbee_test: cfsetispeed failed (%d)", errno); + return -1; + } + + if (cfsetospeed(&termios, speed) < 0) { + error("xbee_test: cfsetospeed failed (%d)", errno); + return -1; + } + + if (tcsetattr(fd, TCSANOW, &termios) < 0) { + error("xbee_test: tcsetattr failed (%d)", errno); + return -1; + } + + return 0; +} + +#ifdef PD + +void xbee_test_setup(void) +{ + xbee_test_class = class_new(gensym("xbee_test"), + (t_newmethod)xbee_test_new, + (t_method)xbee_test_free, + sizeof(t_xbee_test), + CLASS_DEFAULT, + A_GIMME,0); + class_addbang(xbee_test_class, (t_method)xbee_test_bang); + class_addmethod(xbee_test_class, (t_method)xbee_test_dest64, gensym("dest64"), A_DEFSYMBOL, 0); + class_addmethod(xbee_test_class, (t_method)xbee_test_dest16, gensym("dest16"), A_DEFSYMBOL, 0); + class_addmethod(xbee_test_class, (t_method)xbee_test_on, gensym("on"), A_DEFFLOAT, 0); + class_addmethod(xbee_test_class, (t_method)xbee_test_off, gensym("off"), A_DEFFLOAT, 0); +} +#else +int main(void) +{ + t_class *c; + + + c = class_new("xbee_test", (method)xbee_test_new, (method)xbee_test_free, (long)sizeof(t_xbee_test), 0L, A_GIMME, 0); + + class_addmethod(c, (method)xbee_test_bang, "bang", 0); + class_addmethod(c, (method)xbee_test_assist, "assist", A_CANT, 0); + class_addmethod(c, (method)xbee_test_dest64, "dest64", A_DEFSYM, 0); + class_addmethod(c, (method)xbee_test_dest16, "dest16", A_DEFSYM, 0); + class_addmethod(c, (method)xbee_test_on, "on", A_LONG, 0); + class_addmethod(c, (method)xbee_test_off, "off", A_LONG, 0); + + class_register(CLASS_BOX, c); + xbee_test_class = c; + + return 0; +} +#endif /* PD */ + +static void xbee_test_on(t_xbee_test *x, long dpin) +{ + char cmd[2] = "Dx"; + uint8_t param[] = {5}; + xbee_io_context_t *ctx; + int r; + + + if (!x->xbee) + return; + + ctx = xbee_user_context(*(x->xbee)); + if (!ctx) + return; + + if (dpin >= 0 && dpin <= 7) { + cmd[1] = dpin + '0'; + + r = xbee_send_remote_at_cmd(x->xbee, cmd, 1, 2, param, x->dest_addr64, x->dest_addr16); + if (r < 0) { + post("xbee_test: xbee_send_remote_at_cmd failed (%d)", errno); + } + } + + // Nudge IO thread + write(ctx->pipe_fds[1], "!", 1); +} + + +static void xbee_test_off(t_xbee_test *x, long dpin) +{ + char cmd[2] = "Dx"; + uint8_t param[] = {4}; + xbee_io_context_t *ctx; + int r; + + + if (!x->xbee) + return; + + ctx = xbee_user_context(*(x->xbee)); + if (!ctx) + return; + + if (dpin >= 0 && dpin <= 7) { + cmd[1] = dpin + '0'; + + r = xbee_send_remote_at_cmd(x->xbee, cmd, 1, 2, param, x->dest_addr64, x->dest_addr16); + if (r < 0) { + post ("xbee_test: xbee_send_remote_at_cmd failed (%d)", errno); + } + } + + // Nudge IO thread + write(ctx->pipe_fds[1], "!", 1); +} + +#ifndef PD +void xbee_test_assist(t_xbee_test *x, void *b, long m, long a, char *s) +{ + if (m == ASSIST_INLET) { //inlet + sprintf(s, "I am inlet %ld", a); + } + else { // outlet + sprintf(s, "I am outlet %ld", a); + } +} +#endif /* NOT PD */ + +void xbee_test_bang(t_xbee_test *x) +{ +} + + +void xbee_test_close(t_xbee_test *x) +{ + xbee_t *xbee = x->xbee; + xbee_io_context_t *ctx; + + + if (!xbee) + return; + + xbee_kill_io_thread(x->xbee); + + ctx = xbee_user_context(*xbee); + if (!ctx) + return; + + if (ctx->fd >= 0) { + close(ctx->fd); + ctx->fd = -1; + } + + if (ctx->pipe_fds[0] >= 0) { + close(ctx->pipe_fds[0]); + ctx->pipe_fds[0] = -1; + } + + if (ctx->pipe_fds[1] >= 0) { + close(ctx->pipe_fds[1]); + ctx->pipe_fds[1] = -1; + } +} + + +void xbee_test_free(t_xbee_test *x) +{ + xbee_t *xbee = x->xbee; + xbee_io_context_t *ctx; + + + xbee_test_close(x); + if (xbee) { + ctx = xbee_user_context(*xbee); + if (ctx) { + sysmem_freeptr(ctx); + } + + sysmem_freeptr(xbee); + } +} + + +void xbee_test_dest64(t_xbee_test *x, t_symbol *s) +{ + uint64_t dest; + int i; + + + dest = strtoll(s->s_name, NULL, 16); + for (i = 0; i < 8; i++) { + x->dest_addr64[7 - i] = dest & 0xff; + dest >>= 8; + } + + post("xbee_test: set dest64 addr to %02x%02x%02x%02x%02x%02x%02x%02x", + x->dest_addr64[0], x->dest_addr64[1], x->dest_addr64[2], x->dest_addr64[3], + x->dest_addr64[4], x->dest_addr64[5], x->dest_addr64[6], x->dest_addr64[7]); +} + + +void xbee_test_dest16(t_xbee_test *x, t_symbol *s) +{ + uint16_t dest; + int i; + + + dest = strtol(s->s_name, NULL, 16); + for (i = 0; i < 2; i++) { + x->dest_addr16[1 - i] = dest & 0xff; + dest >>= 8; + } + + post("xbee_test: set dest16 addr to %02x%02x", x->dest_addr16[0], x->dest_addr16[1]); +} + + +int xbee_test_open_device(t_xbee_test *x, t_symbol *s) +{ + xbee_io_context_t *xbee_io_context; + int fd; + + + if (s == gensym("")) { + return 0; + } + + xbee_test_close(x); + + xbee_io_context = (xbee_io_context_t *)sysmem_newptr(sizeof(xbee_io_context_t)); + if (xbee_io_context == NULL) { + error("xbee_test: %s: can't allocate memory", s->s_name); + return -1; + } + + memset(xbee_io_context, 0, sizeof(xbee_io_context_t)); + + // Pipe for nudging io thread when there's more data to write + if (pipe(xbee_io_context->pipe_fds) < 0) { + error("xbee_test: %s: can't open pipe (%d)", s->s_name, errno); + sysmem_freeptr(xbee_io_context); + return -1; + } + + fd = open(s->s_name, O_RDWR | O_NONBLOCK, 0); + if (fd < 0) { + error("xbee_test: %s: can't open device file (error %d)", s->s_name, errno); + close(xbee_io_context->pipe_fds[0]); + close(xbee_io_context->pipe_fds[1]); + sysmem_freeptr(xbee_io_context); + return -1; + } + + post("xbee_test: opened %s", s->s_name); + + if (set_baud(fd, x->baud) < 0) { + post("xbee_test: %s: error setting baud to %d", s->s_name, x->baud); + } else { + post("xbee_test: baud set to %d", x->baud); + } + + xbee_io_context->fd = fd; + + xbee_user_context(*(x->xbee)) = xbee_io_context; + + if (xbee_new_io_thread(x->xbee) < 0) { + xbee_user_context(*(x->xbee)) = NULL; + close(fd); + close(xbee_io_context->pipe_fds[0]); + close(xbee_io_context->pipe_fds[1]); + sysmem_freeptr(xbee_io_context); + error("xbee_test: error starting new IO thread"); + return -1; + } + + return 0; +} + + +void *xbee_test_new(t_symbol *s, long argc, t_atom *argv) +{ + t_xbee_test *x = NULL; + t_symbol *a; + + + if (argc < 1) { + error("xbee_test: No device name specified"); + return NULL; + } + + x = (t_xbee_test *)object_alloc(xbee_test_class); + + x->baud = 9600; + + x->xbee = (xbee_t *)sysmem_newptr(sizeof(*x->xbee)); + if (x->xbee == NULL) { + object_free(x); + return NULL; + } + + xbee_init(x->xbee); + + // Set 64-bit destination to 0x0000000000ffff (broadcast) + memset(x->dest_addr64, 0, sizeof(x->dest_addr64)); + x->dest_addr64[7] = 0xff; + x->dest_addr64[6] = 0xff; + + // Set 16-bit destination to 0xfffe (ZNet broadcast) + x->dest_addr16[0] = 0xff; + x->dest_addr16[1] = 0xfe; + + if (argc >= 1) { + if (argc >= 2) { + x->baud = atom_getlong(&argv[1]); + + if (x->baud == 0) { + error("xbee_test: second argument should be a valid baud rate."); + sysmem_freeptr(x->xbee); + object_free(x); + return NULL; + } + } + + a = atom_getsym(&argv[0]); + if (a != gensym("")) { + if (xbee_test_open_device(x, a) < 0) { + sysmem_freeptr(x->xbee); + object_free(x); + return NULL; + } + } + + } + + return (x); +} -- cgit v1.2.1 From 92bf1f78a169ec5e4ac07ff631c112840b03d5dd Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 1 Apr 2010 13:52:32 +0000 Subject: setup with template Makefile svn path=/trunk/externals/io/; revision=13356 --- sixaxis/Makefile | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 235 insertions(+), 10 deletions(-) diff --git a/sixaxis/Makefile b/sixaxis/Makefile index 2b8688b..5e8fe8a 100644 --- a/sixaxis/Makefile +++ b/sixaxis/Makefile @@ -1,17 +1,242 @@ -TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') -EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') +# To use this Makefile for your project, first put the name of your library in +# LIBRARY_NAME variable. The folder for your project should have the same name +# as your library. +LIBRARY_NAME = sixaxis +LIBRARY_VERSION = 0.1 -default: - make -C $(EXTERNALS_ROOT) $(TARGET) +# Next, add your .c source files to the SOURCES variable. The help files will +# be included automatically +SOURCES = + +# For objects that only build on certain platforms, add those to the SOURCES +# line for the right platforms. +SOURCES_android = +SOURCES_cygwin = +SOURCES_macosx = +SOURCES_iphoneos = +SOURCES_linux = sixaxis.c +SOURCES_windows = + +# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will +# be included automatically +PDOBJECTS = + +# if you want to include any other files in the source and binary tarballs, +# list them here. This can be anything from header files, READMEs, example +# patches, documentation, etc. +EXTRA_DIST = + + +#------------------------------------------------------------------------------# +# +# you shouldn't need to edit anything below here, if we did it right :) +# +#------------------------------------------------------------------------------# + +# where Pd lives +PD_PATH = ../../../pd +# where to install the library +prefix = /usr/local +libdir = $(prefix)/lib +pkglibdir = $(libdir)/pd-externals +objectsdir = $(pkglibdir) + + +INSTALL = install +INSTALL_FILE = $(INSTALL) -p -m 644 +INSTALL_DIR = $(INSTALL) -p -m 755 -d + +CFLAGS = -DPD -I$(PD_PATH)/src -Wall -W -g +LDFLAGS = +LIBS = +ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ + $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) + +UNAME := $(shell uname -s) +ifeq ($(UNAME),Darwin) + CPU := $(shell uname -p) + ifeq ($(CPU),arm) # iPhone/iPod Touch + SOURCES += $(SOURCES_macosx) + EXTENSION = pd_darwin + OS = iphoneos + IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin + CC=$(IPHONE_BASE)/gcc + CPP=$(IPHONE_BASE)/cpp + CXX=$(IPHONE_BASE)/g++ + ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk + IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 + OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer + CFLAGS := $(IPHONE_CFLAGS) $(OPT_CFLAGS) $(CFLAGS) \ + -I/Applications/Pd-extended.app/Contents/Resources/include + LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) + LIBS += -lc + STRIP = strip -x + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) + else # Mac OS X + SOURCES += $(SOURCES_macosx) + EXTENSION = pd_darwin + OS = macosx + OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast + FAT_FLAGS = -arch i386 -arch ppc -mmacosx-version-min=10.4 + CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include \ + -I/Applications/Pd-extended.app/Contents/Resources/include + LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib + # if the 'pd' binary exists, check the linking against it to aid with stripping + LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd) + LIBS += -lc + STRIP = strip -x + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) + endif +endif +ifeq ($(UNAME),Linux) + SOURCES += $(SOURCES_linux) + EXTENSION = pd_linux + OS = linux + OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer + CFLAGS += -fPIC + LDFLAGS += -Wl,--export-dynamic -shared -fPIC + LIBS += -lc + STRIP = strip --strip-unneeded -R .note -R .comment + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) +endif +ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) + SOURCES += $(SOURCES_cygwin) + EXTENSION = dll + OS = cygwin + OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer + CFLAGS += + LDFLAGS += -Wl,--export-dynamic -shared -L$(PD_PATH)/src + LIBS += -lc -lpd + STRIP = strip --strip-unneeded -R .note -R .comment + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) +endif +ifeq (MINGW,$(findstring MINGW,$(UNAME))) + SOURCES += $(SOURCES_windows) + EXTENSION = dll + OS = windows + OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -march=i686 -mtune=pentium4 + WINDOWS_HACKS = -D'O_NONBLOCK=1' + CFLAGS += -mms-bitfields $(WINDOWS_HACKS) + LDFLAGS += -s -shared -Wl,--enable-auto-import + LIBS += -L$(PD_PATH)/src -L$(PD_PATH)/bin -L$(PD_PATH)/obj -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 + STRIP = strip --strip-unneeded -R .note -R .comment + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) +endif + +CFLAGS += $(OPT_CFLAGS) + + +.PHONY = install libdir_install single_install install-doc install-exec install-examples clean dist etags + +all: $(SOURCES:.c=.$(EXTENSION)) + +%.o: %.c + $(CC) $(CFLAGS) -o "$*.o" -c "$*.c" + +%.$(EXTENSION): %.o + $(CC) $(LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(LIBS) + chmod a-x "$*.$(EXTENSION)" + +# this links everything into a single binary file +$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o + $(CC) $(LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(LIBS) + chmod a-x $(LIBRARY_NAME).$(EXTENSION) + + +install: libdir_install + +# The meta and help files are explicitly installed to make sure they are +# actually there. Those files are not optional, then need to be there. +libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(SOURCES))" || (\ + $(INSTALL_FILE) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ + $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + +# install library linked as single binary +single_install: $(LIBRARY_NAME) install-doc install-exec + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + $(INSTALL_FILE) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) + +install-doc: + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(SOURCES))" || \ + $(INSTALL_FILE) $(SOURCES:.c=-help.pd) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS:.pd=-help.pd) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) +# this is the only bit not really handled well... + $(INSTALL_FILE) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/ + +install-examples: + test ! -d examples || (\ + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ + $(INSTALL_FILE) examples/*.* $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples) -install: - make -C $(EXTERNALS_ROOT) $(TARGET)_install clean: - make -C $(EXTERNALS_ROOT) $(TARGET)_clean + -rm -f -- $(SOURCES:.c=.o) + -rm -f -- $(SOURCES:.c=.$(EXTENSION)) + -rm -f -- $(LIBRARY_NAME).$(EXTENSION) + +distclean: clean + -rm -f -- $(DISTBINDIR).tar.gz + -rm -rf -- $(DISTBINDIR) + -rm -f -- $(DISTDIR).tar.gz + -rm -rf -- $(DISTDIR) + + +$(DISTBINDIR): + $(INSTALL_DIR) $(DISTBINDIR) + +libdir: all $(DISTBINDIR) + $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) + $(INSTALL_FILE) $(SOURCES) $(DISTBINDIR) + $(INSTALL_FILE) $(SOURCES:.c=-help.pd) $(DISTBINDIR) + test -z "$(strip $(EXTRA_DIST))" || \ + $(INSTALL_FILE) $(EXTRA_DIST) $(DISTBINDIR) +# tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) + +$(DISTDIR): + $(INSTALL_DIR) $(DISTDIR) + +dist: $(DISTDIR) + $(INSTALL_FILE) Makefile $(DISTDIR) + $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd $(DISTDIR) + test -z "$(strip $(ALLSOURCES))" || \ + $(INSTALL_FILE) $(ALLSOURCES) $(DISTDIR) + test -z "$(strip $(ALLSOURCES))" || \ + $(INSTALL_FILE) $(ALLSOURCES:.c=-help.pd) $(DISTDIR) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS) $(DISTDIR) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS:.pd=-help.pd) $(DISTDIR) + test -z "$(strip $(EXTRA_DIST))" || \ + $(INSTALL_FILE) $(EXTRA_DIST) $(DISTDIR) + tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) -test_locations: - make -C $(EXTERNALS_ROOT) test_locations etags: - etags *.[ch] ~/code/pure-data/trunk/pd/src/*.[ch] /usr/include/*.h /usr/include/sys/*.h + etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h + +showpaths: + @echo "PD_PATH: $(PD_PATH)" + @echo "objectsdir: $(objectsdir)" + @echo "LIBRARY_NAME: $(LIBRARY_NAME)" + @echo "SOURCES: $(SOURCES)" + @echo "ALLSOURCES: $(ALLSOURCES)" + @echo "UNAME: $(UNAME)" + @echo "CPU: $(CPU)" + -- cgit v1.2.1 From 9cf556c62054af9990e99fd331aa5e2135caae4a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 1 Apr 2010 14:12:42 +0000 Subject: setup with template Makefile svn path=/trunk/externals/io/; revision=13358 --- xbee/Makefile | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 237 insertions(+), 26 deletions(-) diff --git a/xbee/Makefile b/xbee/Makefile index e222c9b..cee7adb 100644 --- a/xbee/Makefile +++ b/xbee/Makefile @@ -1,33 +1,244 @@ -TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|') -EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|') +# To use this Makefile for your project, first put the name of your library in +# LIBRARY_NAME variable. The folder for your project should have the same name +# as your library. +LIBRARY_NAME = xbee +LIBRARY_VERSION = 0.1 -default: - make -C $(EXTERNALS_ROOT) $(TARGET) +# Next, add your .c source files to the SOURCES variable. The help files will +# be included automatically +SOURCES = + +# For objects that only build on certain platforms, add those to the SOURCES +# line for the right platforms. +SOURCES_android = +SOURCES_cygwin = +SOURCES_macosx = xbee_test.c +SOURCES_iphoneos = +SOURCES_linux = +SOURCES_windows = + +# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will +# be included automatically +PDOBJECTS = + +# if you want to include any other files in the source and binary tarballs, +# list them here. This can be anything from header files, READMEs, example +# patches, documentation, etc. +EXTRA_DIST = max2pd.h xbee.h xbee.c xbee_io.h xbee_io.c xbee_protocol.h + + +#------------------------------------------------------------------------------# +# +# you shouldn't need to edit anything below here, if we did it right :) +# +#------------------------------------------------------------------------------# + +# where Pd lives +PD_PATH = ../../../pd +# where to install the library +prefix = /usr/local +libdir = $(prefix)/lib +pkglibdir = $(libdir)/pd-externals +objectsdir = $(pkglibdir) + + +INSTALL = install +INSTALL_FILE = $(INSTALL) -p -m 644 +INSTALL_DIR = $(INSTALL) -p -m 755 -d + +CFLAGS = -DPD -I$(PD_PATH)/src -Wall -W -g +LDFLAGS = +LIBS = -lusb -lhid +ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ + $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) + +UNAME := $(shell uname -s) +ifeq ($(UNAME),Darwin) + CPU := $(shell uname -p) + ifeq ($(CPU),arm) # iPhone/iPod Touch + SOURCES += $(SOURCES_macosx) + EXTENSION = pd_darwin + OS = iphoneos + IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin + CC=$(IPHONE_BASE)/gcc + CPP=$(IPHONE_BASE)/cpp + CXX=$(IPHONE_BASE)/g++ + ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk + IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 + OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer + CFLAGS := $(IPHONE_CFLAGS) $(OPT_CFLAGS) $(CFLAGS) \ + -I/Applications/Pd-extended.app/Contents/Resources/include + LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) + LIBS += -lc + STRIP = strip -x + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) + else # Mac OS X + SOURCES += $(SOURCES_macosx) + EXTENSION = pd_darwin + OS = macosx + OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast + FAT_FLAGS = -arch i386 -arch ppc -mmacosx-version-min=10.4 + CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include \ + -I/Applications/Pd-extended.app/Contents/Resources/include + LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib + # if the 'pd' binary exists, check the linking against it to aid with stripping + LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd) + LIBS += -lc + STRIP = strip -x + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) + endif +endif +ifeq ($(UNAME),Linux) + SOURCES += $(SOURCES_linux) + EXTENSION = pd_linux + OS = linux + OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer + CFLAGS += -fPIC + LDFLAGS += -Wl,--export-dynamic -shared -fPIC + LIBS += -lc + STRIP = strip --strip-unneeded -R .note -R .comment + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) +endif +ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) + SOURCES += $(SOURCES_cygwin) + EXTENSION = dll + OS = cygwin + OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer + CFLAGS += + LDFLAGS += -Wl,--export-dynamic -shared -L$(PD_PATH)/src + LIBS += -lc -lpd + STRIP = strip --strip-unneeded -R .note -R .comment + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) +endif +ifeq (MINGW,$(findstring MINGW,$(UNAME))) + SOURCES += $(SOURCES_windows) + EXTENSION = dll + OS = windows + OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -march=i686 -mtune=pentium4 + WINDOWS_HACKS = -D'O_NONBLOCK=1' + CFLAGS += -mms-bitfields $(WINDOWS_HACKS) + LDFLAGS += -s -shared -Wl,--enable-auto-import + LIBS += -L$(PD_PATH)/src -L$(PD_PATH)/bin -L$(PD_PATH)/obj -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 + STRIP = strip --strip-unneeded -R .note -R .comment + DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) + DISTBINDIR=$(DISTDIR)-$(OS) +endif + +CFLAGS += $(OPT_CFLAGS) + + +.PHONY = install libdir_install single_install install-doc install-exec install-examples clean dist etags + +all: $(SOURCES:.c=.$(EXTENSION)) + +%.o: %.c + $(CC) $(CFLAGS) -o "$*.o" -c "$*.c" + +%.$(EXTENSION): %.o + $(CC) $(LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(LIBS) + chmod a-x "$*.$(EXTENSION)" + +# this links everything into a single binary file +$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o + $(CC) $(LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(LIBS) + chmod a-x $(LIBRARY_NAME).$(EXTENSION) + + +install: libdir_install + +# The meta and help files are explicitly installed to make sure they are +# actually there. Those files are not optional, then need to be there. +libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(SOURCES))" || (\ + $(INSTALL_FILE) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ + $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + +# install library linked as single binary +single_install: $(LIBRARY_NAME) install-doc install-exec + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + $(INSTALL_FILE) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) + +install-doc: + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(SOURCES))" || \ + $(INSTALL_FILE) $(SOURCES:.c=-help.pd) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS:.pd=-help.pd) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) +# this is the only bit not really handled well... + $(INSTALL_FILE) README $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt + $(INSTALL_FILE) VERSION $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/VERSION.txt + $(INSTALL_FILE) CHANGES $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/CHANGES.txt + +install-examples: + test ! -d examples || (\ + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ + $(INSTALL_FILE) examples/*.* $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples) -install: - make -C $(EXTERNALS_ROOT) $(TARGET)_install clean: - make -C $(EXTERNALS_ROOT) $(TARGET)_clean + -rm -f -- $(SOURCES:.c=.o) + -rm -f -- $(SOURCES:.c=.$(EXTENSION)) + -rm -f -- $(LIBRARY_NAME).$(EXTENSION) + +distclean: clean + -rm -f -- $(DISTBINDIR).tar.gz + -rm -rf -- $(DISTBINDIR) + -rm -f -- $(DISTDIR).tar.gz + -rm -rf -- $(DISTDIR) + + +$(DISTBINDIR): + $(INSTALL_DIR) $(DISTBINDIR) + +libdir: all $(DISTBINDIR) + $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) + $(INSTALL_FILE) $(SOURCES) $(DISTBINDIR) + $(INSTALL_FILE) $(SOURCES:.c=-help.pd) $(DISTBINDIR) + test -z "$(strip $(EXTRA_DIST))" || \ + $(INSTALL_FILE) $(EXTRA_DIST) $(DISTBINDIR) +# tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) + +$(DISTDIR): + $(INSTALL_DIR) $(DISTDIR) + +dist: $(DISTDIR) + $(INSTALL_FILE) Makefile $(DISTDIR) + $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd $(DISTDIR) + test -z "$(strip $(ALLSOURCES))" || \ + $(INSTALL_FILE) $(ALLSOURCES) $(DISTDIR) + test -z "$(strip $(ALLSOURCES))" || \ + $(INSTALL_FILE) $(ALLSOURCES:.c=-help.pd) $(DISTDIR) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS) $(DISTDIR) + test -z "$(strip $(PDOBJECTS))" || \ + $(INSTALL_FILE) $(PDOBJECTS:.pd=-help.pd) $(DISTDIR) + test -z "$(strip $(EXTRA_DIST))" || \ + $(INSTALL_FILE) $(EXTRA_DIST) $(DISTDIR) + tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) -test_locations: - make -C $(EXTERNALS_ROOT) test_locations -# for emacs etags: - etags ../../../pd/src/*.h *.[ch] - make etags_`uname -s` - -etags_Darwin: - etags -a \ - /System/Library/Frameworks/ForceFeedback.framework/Headers/*.h \ - /System/Library/Frameworks/CoreFoundation.framework/Headers/*.h \ - /System/Library/Frameworks/Carbon.framework/Headers/*.h \ - /System/Library/Frameworks/IOBluetooth.framework/Headers/*.[ch] - -etags_Linux: - etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h - -etags_MINGW: - etags -a /usr/include/*.h /usr/include/sys/*.h \ - /usr/local/include/*.h /usr/local/include/sys/*.h + etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h + +showpaths: + @echo "PD_PATH: $(PD_PATH)" + @echo "objectsdir: $(objectsdir)" + @echo "LIBRARY_NAME: $(LIBRARY_NAME)" + @echo "SOURCES: $(SOURCES)" + @echo "ALLSOURCES: $(ALLSOURCES)" + @echo "UNAME: $(UNAME)" + @echo "CPU: $(CPU)" + -- cgit v1.2.1 From e0d1bd98943fd82b2a1456946fda28e1c59a52f2 Mon Sep 17 00:00:00 2001 From: mescalinum Date: Wed, 15 Sep 2010 12:37:05 +0000 Subject: remove -mcpu/-mtune flags as it breaks x64 build. we should eventually figure a way of determining automatically the CPU, but 'uname -m' doesn't tell the truth svn path=/trunk/externals/io/; revision=14145 --- sixaxis/Makefile | 2 +- xbee/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sixaxis/Makefile b/sixaxis/Makefile index 5e8fe8a..51c9331 100644 --- a/sixaxis/Makefile +++ b/sixaxis/Makefile @@ -118,7 +118,7 @@ ifeq (MINGW,$(findstring MINGW,$(UNAME))) SOURCES += $(SOURCES_windows) EXTENSION = dll OS = windows - OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -march=i686 -mtune=pentium4 + OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer WINDOWS_HACKS = -D'O_NONBLOCK=1' CFLAGS += -mms-bitfields $(WINDOWS_HACKS) LDFLAGS += -s -shared -Wl,--enable-auto-import diff --git a/xbee/Makefile b/xbee/Makefile index cee7adb..b7e3c40 100644 --- a/xbee/Makefile +++ b/xbee/Makefile @@ -118,7 +118,7 @@ ifeq (MINGW,$(findstring MINGW,$(UNAME))) SOURCES += $(SOURCES_windows) EXTENSION = dll OS = windows - OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -march=i686 -mtune=pentium4 + OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer WINDOWS_HACKS = -D'O_NONBLOCK=1' CFLAGS += -mms-bitfields $(WINDOWS_HACKS) LDFLAGS += -s -shared -Wl,--enable-auto-import -- cgit v1.2.1