├── .gitmodules ├── LICENSE ├── firmware ├── LUFAConfig.h ├── arduino_leonardo │ ├── devconfig.h │ ├── hwconfig.h │ ├── makefile │ ├── pinmap.h │ └── readme.txt ├── arduino_mega2560 │ ├── devconfig.h │ ├── m16u2 │ │ ├── hwconfig.h │ │ └── makefile │ ├── m2560 │ │ ├── hwconfig.h │ │ ├── makefile │ │ └── pinmap.h │ ├── makefile │ └── readme.txt ├── arduino_promicro │ ├── devconfig.h │ ├── hwconfig.h │ ├── makefile │ └── pinmap.h ├── arduino_uno │ ├── devconfig.h │ ├── m328 │ │ ├── hwconfig.h │ │ ├── makefile │ │ └── pinmap.h │ ├── m8u2 │ │ ├── hwconfig.h │ │ └── makefile │ ├── makefile │ └── readme.txt ├── breakout_32u2 │ ├── devconfig.h │ ├── hwconfig.h │ ├── makefile │ └── pinmap.h ├── clock.c ├── clock.h ├── comm.c ├── comm.h ├── data_uart0.h ├── data_uart1.h ├── default.mk ├── descriptors.c ├── descriptors.h ├── keydefs.h ├── led.c ├── led.h ├── lufa.mk ├── main_led.c ├── main_usb.c ├── makefile ├── panel.c ├── panel.h ├── queue.c └── queue.h ├── readme.txt ├── schematic ├── breakout32u2.brd └── breakout32u2.sch └── win32 ├── driver ├── build │ ├── vs_2008 │ │ ├── ledwiz.sln │ │ └── ledwiz.vcproj │ └── vs_2012 │ │ ├── ledwiz.sln │ │ ├── ledwiz.vcxproj │ │ └── ledwiz.vcxproj.filters ├── include │ └── ledwiz.h └── src │ ├── ledwiz.cpp │ ├── ledwiz.def │ ├── usbdev.cpp │ └── usbdev.h ├── lwcconfig ├── build │ └── vs_2008 │ │ ├── lwcconfig.sln │ │ └── lwcconfig.vcproj └── src │ └── main.cpp └── testapp ├── build ├── vs_2008 │ ├── testapp.sln │ └── testapp.vcproj └── vs_2012 │ ├── testapp.sln │ ├── testapp.vcxproj │ └── testapp.vcxproj.filters └── src └── main.cpp /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "firmware/lufa"] 2 | path = firmware/lufa 3 | url = https://github.com/abcminiuser/lufa.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /firmware/LUFAConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /* 18 | LUFA Library 19 | Copyright (C) Dean Camera, 2012. 20 | 21 | dean [at] fourwalledcubicle [dot] com 22 | www.lufa-lib.org 23 | */ 24 | 25 | /* 26 | Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) 27 | 28 | Permission to use, copy, modify, distribute, and sell this 29 | software and its documentation for any purpose is hereby granted 30 | without fee, provided that the above copyright notice appear in 31 | all copies and that both that the copyright notice and this 32 | permission notice and warranty disclaimer appear in supporting 33 | documentation, and that the name of the author not be used in 34 | advertising or publicity pertaining to distribution of the 35 | software without specific, written prior permission. 36 | 37 | The author disclaim all warranties with regard to this 38 | software, including all implied warranties of merchantability 39 | and fitness. In no event shall the author be liable for any 40 | special, indirect or consequential damages or any damages 41 | whatsoever resulting from loss of use, data or profits, whether 42 | in an action of contract, negligence or other tortious action, 43 | arising out of or in connection with the use or performance of 44 | this software. 45 | */ 46 | 47 | /** \file 48 | * \brief LUFA Library Configuration Header File 49 | * 50 | * This header file is used to configure LUFA's compile time options, 51 | * as an alternative to the compile time constants supplied through 52 | * a makefile. 53 | * 54 | * For information on what each token does, refer to the LUFA 55 | * manual section "Summary of Compile Tokens". 56 | */ 57 | 58 | #ifndef _LUFA_CONFIG_H_ 59 | #define _LUFA_CONFIG_H_ 60 | 61 | #if (ARCH == ARCH_AVR8) 62 | 63 | /* Non-USB Related Configuration Tokens: */ 64 | // #define DISABLE_TERMINAL_CODES 65 | 66 | /* USB Class Driver Related Tokens: */ 67 | // #define HID_HOST_BOOT_PROTOCOL_ONLY 68 | // #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} 69 | // #define HID_USAGE_STACK_DEPTH {Insert Value Here} 70 | // #define HID_MAX_COLLECTIONS {Insert Value Here} 71 | // #define HID_MAX_REPORTITEMS {Insert Value Here} 72 | // #define HID_MAX_REPORT_IDS {Insert Value Here} 73 | // #define NO_CLASS_DRIVER_AUTOFLUSH 74 | 75 | /* General USB Driver Related Tokens: */ 76 | // #define ORDERED_EP_CONFIG 77 | #define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL) 78 | #define USB_DEVICE_ONLY 79 | // #define USB_HOST_ONLY 80 | // #define USB_STREAM_TIMEOUT_MS {Insert Value Here} 81 | // #define NO_LIMITED_CONTROLLER_CONNECT 82 | // #define NO_SOF_EVENTS 83 | 84 | /* USB Device Mode Driver Related Tokens: */ 85 | // #define USE_RAM_DESCRIPTORS 86 | // #define USE_FLASH_DESCRIPTORS 87 | // #define USE_EEPROM_DESCRIPTORS 88 | // #define NO_INTERNAL_SERIAL 89 | #define FIXED_CONTROL_ENDPOINT_SIZE 8 90 | // #define DEVICE_STATE_AS_GPIOR {Insert Value Here} 91 | #define FIXED_NUM_CONFIGURATIONS 1 92 | // #define CONTROL_ONLY_DEVICE 93 | // #define INTERRUPT_CONTROL_ENDPOINT 94 | // #define NO_DEVICE_REMOTE_WAKEUP 95 | // #define NO_DEVICE_SELF_POWER 96 | 97 | /* USB Host Mode Driver Related Tokens: */ 98 | // #define HOST_STATE_AS_GPIOR {Insert Value Here} 99 | // #define USB_HOST_TIMEOUT_MS {Insert Value Here} 100 | // #define HOST_DEVICE_SETTLE_DELAY_MS {Insert Value Here} 101 | // #define NO_AUTO_VBUS_MANAGEMENT 102 | // #define INVERTED_VBUS_ENABLE_LINE 103 | 104 | #else 105 | 106 | #error Unsupported architecture for this LUFA configuration file. 107 | 108 | #endif 109 | #endif 110 | -------------------------------------------------------------------------------- /firmware/arduino_leonardo/devconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DEVCONFIG_H__INCLUDED 18 | #define DEVCONFIG_H__INCLUDED 19 | 20 | 21 | /**************************************** 22 | USB device config 23 | ****************************************/ 24 | 25 | #define ENABLE_LED_DEVICE 26 | 27 | 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /firmware/arduino_leonardo/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #if (F_CPU != 16000000) 21 | #error "invalid CPU clock frequency ==> should be 16 MHZ" 22 | #endif 23 | 24 | #if !defined(__AVR_ATmega32U4__) 25 | #error "invalid CPU type ==> should be ATMega32u4" 26 | #endif 27 | 28 | #include "devconfig.h" 29 | #include "pinmap.h" 30 | 31 | 32 | /**************************************** 33 | LED driver config 34 | ****************************************/ 35 | 36 | #if defined(ENABLE_LED_DEVICE) 37 | 38 | #define LED_TIMER_vect TIMER0_COMPA_vect 39 | 40 | static void inline led_timer_init(void) 41 | { 42 | const int T0_CYCLE_US = 200; 43 | OCR0A = (((T0_CYCLE_US * (F_CPU / 1000L)) / (64 * 1000L)) - 1); 44 | TCCR0A = _BV(WGM01); // clear timer/counter on compare0 match 45 | TCCR0B = _BV(CS01) |_BV(CS00); // prescale 64 46 | TIMSK0 = _BV(OCIE0A); // enable Output Compare 0 overflow interrupt 47 | TCNT0 = 0x00; 48 | } 49 | 50 | #endif 51 | 52 | 53 | /**************************************** 54 | Panel config 55 | ****************************************/ 56 | 57 | #if defined(ENABLE_PANEL_DEVICE) 58 | #define PANEL_TASK 59 | #endif 60 | 61 | 62 | /**************************************** 63 | Clock config 64 | ****************************************/ 65 | 66 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 67 | #define CLOCK_TCNT TCNT1 68 | #define CLOCK_OCR OCR1A 69 | 70 | static void inline clock_init(void) 71 | { 72 | OCR1A = TCNT1 + (F_CPU / 1000); 73 | TCCR1B = _BV(CS10); // normal mode, no prescale 74 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 75 | } 76 | 77 | 78 | /**************************************** 79 | Debug UART config 80 | ****************************************/ 81 | 82 | #if defined(DEBUGLEVEL) 83 | 84 | #define DEBUG_TX_UART_vect USART1_UDRE_vect 85 | 86 | static void inline debug_uart_setUDRIE(uint8_t x) { if (x) { UCSR1B |= (1 << UDRIE1); } else { UCSR1B &= ~(1 << UDRIE1); } } 87 | static void inline debug_uart_writeUDR(uint8_t x) { UDR1 = x; } 88 | 89 | static void inline debug_uart_init(void) 90 | { 91 | UBRR1 = 16; // 115200 bit/s @ 16MHz (==> 2.1% error) 92 | UCSR1A |= (1 << U2X1); 93 | UCSR1C = (3 << UCSZ10); // 1 stop, 8 data 94 | UCSR1B |= (1 << TXEN1); 95 | } 96 | 97 | #endif 98 | 99 | 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /firmware/arduino_leonardo/makefile: -------------------------------------------------------------------------------- 1 | 2 | TARGET = arduino_leonardo 3 | TARGET_PATH = ./arduino_leonardo 4 | PARENT_PATH = ./.. 5 | MCU = atmega32u4 6 | F_CPU = 16000000 7 | LWCLONE_SRC = ../main_usb.c ../descriptors.c ../comm.c ../led.c ../panel.c ../queue.c ../clock.c 8 | 9 | include ../lufa.mk 10 | -------------------------------------------------------------------------------- /firmware/arduino_leonardo/pinmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #define LED_MAPPING_TABLE(_map_) \ 18 | /* the following corresponds to the Arduino Leonardo mapping */ \ 19 | \ 20 | _map_( F, 7, 0 ) /* Analog Pin 0 */ \ 21 | _map_( F, 6, 0 ) /* Analog Pin 1 */ \ 22 | _map_( F, 5, 0 ) /* Analog Pin 2 */ \ 23 | _map_( F, 4, 0 ) /* Analog Pin 3 */ \ 24 | _map_( F, 1, 0 ) /* Analog Pin 4 */ \ 25 | _map_( F, 0, 0 ) /* Analog Pin 5 */ \ 26 | \ 27 | _map_( D, 2, 0 ) /* Digital Pin 0 */ \ 28 | _map_( D, 3, 0 ) /* Digital Pin 1 */ \ 29 | _map_( D, 1, 0 ) /* Digital Pin 2 */ \ 30 | _map_( D, 0, 0 ) /* Digital Pin 3 */ \ 31 | _map_( D, 4, 0 ) /* Digital Pin 4 */ \ 32 | _map_( C, 6, 0 ) /* Digital Pin 5 */ \ 33 | _map_( D, 7, 0 ) /* Digital Pin 6 */ \ 34 | _map_( E, 6, 0 ) /* Digital Pin 7 */ \ 35 | _map_( B, 4, 0 ) /* Digital Pin 8 */ \ 36 | _map_( B, 5, 0 ) /* Digital Pin 9 */ \ 37 | _map_( B, 6, 0 ) /* Digital Pin 10 */ \ 38 | _map_( B, 7, 0 ) /* Digital Pin 11 */ \ 39 | _map_( D, 6, 0 ) /* Digital Pin 12 */ \ 40 | _map_( C, 7, 0 ) /* Digital Pin 13 (L LED) */ \ 41 | \ 42 | _map_( B, 0, 1 ) /* RX LED */ \ 43 | _map_( D, 5, 1 ) /* TX LED */ \ 44 | \ 45 | _map_( B, 1, 0 ) /* SCK */ \ 46 | _map_( B, 2, 0 ) /* MOSI */ \ 47 | _map_( B, 3, 0 ) /* MISO */ \ 48 | \ 49 | /* end */ 50 | -------------------------------------------------------------------------------- /firmware/arduino_leonardo/readme.txt: -------------------------------------------------------------------------------- 1 | To upload the firmware the Leonardo has to put into bootloader mode by pressing the reset button. 2 | It will then appear at your PC as a serial device with a specific COM port, e.g. COM7. 3 | Quickly before it leaves the bootloader due to timeout, run avrdude: 4 | 5 | avrdude -c avr109 -p atmega32u4 -P COM7 -U flash:w:arduino_leonardo.hex:i 6 | 7 | where you have to adjust this line with the respective com port. 8 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/devconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DEVCONFIG_H__INCLUDED 18 | #define DEVCONFIG_H__INCLUDED 19 | 20 | 21 | /**************************************** 22 | USB device config 23 | ****************************************/ 24 | 25 | #define ENABLE_LED_DEVICE 26 | 27 | #define ENABLE_PANEL_DEVICE 28 | #define NUM_JOYSTICKS 2 29 | #define USE_MOUSE 0 30 | #define USE_CONSUMER 1 31 | #define USE_KEYBOARD 1 32 | 33 | 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/m16u2/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #if (F_CPU != 16000000) 21 | #error "invalid CPU clock frequency ==> should be 16 MHZ" 22 | #endif 23 | 24 | #if !defined(__AVR_ATmega8U2__) && !defined(__AVR_ATmega16U2__) && !defined(__AVR_ATmega32U2__) 25 | #error "invalid CPU type ==> should be atmega8u2/16u2/32u2" 26 | #endif 27 | 28 | #include 29 | #include "../devconfig.h" 30 | 31 | 32 | /**************************************** 33 | Data UART config 34 | ****************************************/ 35 | 36 | #define DATA_TX_UART_vect USART1_UDRE_vect 37 | #define DATA_RX_UART_vect USART1_RX_vect 38 | 39 | #include "../../data_uart1.h" 40 | 41 | static void inline data_uart_init(void) 42 | { 43 | UBRR1 = 3; // 250 kBit/s @ 16 MHz CPU 44 | UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10) | (1 << UPM11) | (1 << UPM10); // asynchron uart, odd parity, 9-bit-character, 1 stop bit 45 | UCSR1B |= (1 << UCSZ12) | (1 << TXEN1) | (1 << RXEN1) | (1 << RXCIE1); // enable Receiver and Transmitter 46 | } 47 | 48 | 49 | /**************************************** 50 | Clock config 51 | ****************************************/ 52 | 53 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 54 | #define CLOCK_TCNT TCNT1 55 | #define CLOCK_OCR OCR1A 56 | 57 | static void inline clock_init(void) 58 | { 59 | OCR1A = TCNT1 + (F_CPU / 1000); 60 | TCCR1B = _BV(CS10); // normal mode, no prescale 61 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 62 | } 63 | 64 | 65 | /**************************************** 66 | Bootloader shutdown config 67 | ****************************************/ 68 | 69 | #define exit_bootloader(x) exit_bootloader_stk500v2(x) 70 | #include 71 | 72 | static void inline exit_bootloader_stk500v2(void) 73 | { 74 | UBRR1 = 16; // 115200 bit/s @ 16MHz (==> 2.1% error) 75 | UCSR1A |= (1 << U2X1); 76 | UCSR1B |= (1 << TXEN1); 77 | 78 | _delay_ms(70); // wait until the uC is active (worst case: 65ms + 14CK with LFUSE=0xFF) and waits for data 79 | 80 | #define SEND(_b_) do { \ 81 | loop_until_bit_is_set(UCSR1A, UDRE1); \ 82 | UDR1 = _b_; } while(0) 83 | 84 | SEND(0x1B); // message start 85 | SEND(0); // sequence number 86 | SEND(0); // message size high 87 | SEND(3); // message size low 88 | SEND(0x0E); // token 89 | SEND(0x11); // command id "leave progmode" 90 | SEND(0); // pre delay 91 | SEND(0); // post delay 92 | SEND(0x1B ^ 3 ^ 0x0e ^ 0x11); // checksum 93 | 94 | _delay_ms(60); // wait until the bootloader has replied and exited (50 ms minimum for shutting down the LEDs --> see stk500boot.c) 95 | UCSR1A &= ~(1 << U2X1); // restore previous state of the uart 96 | UCSR1B &= ~(1 << TXEN1); 97 | 98 | #undef SEND 99 | } 100 | 101 | 102 | #define BOOTLOADER_SIZE 4096 103 | #define BOOTLOADER_START_ADDR ((uint8_t*)1 + FLASHEND - BOOTLOADER_SIZE) 104 | 105 | 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/m16u2/makefile: -------------------------------------------------------------------------------- 1 | 2 | TARGET = arduino_mega2560__m16u2 3 | TARGET_PATH = ./arduino_mega2560/m16u2 4 | PARENT_PATH = ../.. 5 | MCU = atmega16u2 6 | F_CPU = 16000000 7 | LWCLONE_SRC = ../../main_usb.c ../../descriptors.c ../../comm.c ../../led.c ../../panel.c ../../queue.c ../../clock.c 8 | CFLAGS = -I./. 9 | 10 | include ../../lufa.mk 11 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/m2560/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #include 21 | #include 22 | 23 | #if (F_CPU != 16000000) 24 | #error "invalid CPU clock frequency ==> should be 16 MHZ" 25 | #endif 26 | 27 | #if !defined(__AVR_ATmega2560__ ) 28 | #error "invalid CPU type ==> should be ATMega2560" 29 | #endif 30 | 31 | #include "../devconfig.h" 32 | #include "pinmap.h" 33 | 34 | 35 | /**************************************** 36 | LED driver config 37 | ****************************************/ 38 | 39 | #if defined(ENABLE_LED_DEVICE) 40 | 41 | #define LED_TIMER_vect TIMER0_COMPA_vect 42 | 43 | static void inline led_timer_init(void) 44 | { 45 | const int T0_CYCLE_US = 200; 46 | OCR0A = (((T0_CYCLE_US * (F_CPU / 1000L)) / (64 * 1000L)) - 1); 47 | TCCR0A = _BV(WGM01); // clear timer/counter on compare0 match 48 | TCCR0B = _BV(CS01) |_BV(CS00); // prescale 64 49 | TIMSK0 = _BV(OCIE0A); // enable Output Compare 0 overflow interrupt 50 | TCNT0 = 0x00; 51 | } 52 | 53 | #endif 54 | 55 | 56 | /**************************************** 57 | Panel config 58 | ****************************************/ 59 | 60 | #if defined(ENABLE_PANEL_DEVICE) 61 | #define PANEL_TASK 62 | #endif 63 | 64 | 65 | /**************************************** 66 | ADC config 67 | ****************************************/ 68 | 69 | #if defined(ENABLE_ANALOG_INPUT) 70 | 71 | static void inline ADC_init(void) 72 | { 73 | ADMUX = (1 << REFS0); // VCC with external capacitor on ARef pin 74 | 75 | ADCSRA = 76 | (1 << ADEN) | //enable 77 | (1 << ADSC) | //start conversion(s) 78 | (1 << ADIE) | // interrupt enable 79 | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler 128x 80 | } 81 | 82 | // https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf 83 | // page 266 : 25.2.1 84 | #define ADCSRB_MUX5 3 85 | 86 | static void inline ADC_setmux(uint8_t mux) 87 | { 88 | ADMUX &= ~0x1F; 89 | ADMUX |= mux & 0x1F; 90 | ADCSRB &= ~(1 << ADCSRB_MUX5); 91 | ADCSRB |= (((mux >> 5) & 0x01) << ADCSRB_MUX5); 92 | } 93 | 94 | #endif 95 | 96 | 97 | /**************************************** 98 | Clock config 99 | ****************************************/ 100 | 101 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 102 | #define CLOCK_TCNT TCNT1 103 | #define CLOCK_OCR OCR1A 104 | 105 | static void inline clock_init(void) 106 | { 107 | OCR1A = TCNT1 + (F_CPU / 1000); 108 | TCCR1B = _BV(CS10); // normal mode, no prescale 109 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 110 | } 111 | 112 | 113 | /**************************************** 114 | Data UART config 115 | ****************************************/ 116 | 117 | #define DATA_TX_UART_vect USART0_UDRE_vect 118 | #define DATA_RX_UART_vect USART0_RX_vect 119 | 120 | #include "../../data_uart0.h" 121 | 122 | static void inline data_uart_init(void) 123 | { 124 | UBRR0 = 3; // 250 kBit/s @ 16 MHz CPU 125 | UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00) | (1 << UPM01) | (1 << UPM00); // asynchron uart, odd parity, 9-bit-character, 1 stop bit 126 | UCSR0B |= (1 << UCSZ02) | (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0); // enable Receiver and Transmitter 127 | } 128 | 129 | 130 | /**************************************** 131 | Debug UART config 132 | ****************************************/ 133 | 134 | #if defined(DEBUGLEVEL) 135 | 136 | #define DEBUG_TX_UART_vect USART1_UDRE_vect 137 | 138 | static void inline debug_uart_setUDRIE(uint8_t x) { if (x) { UCSR1B |= (1 << UDRIE1); } else { UCSR1B &= ~(1 << UDRIE1); } } 139 | static void inline debug_uart_writeUDR(uint8_t x) { UDR1 = x; } 140 | 141 | static void inline debug_uart_init(void) 142 | { 143 | UBRR1 = 16; // 115200 bit/s @ 16MHz (==> 2.1% error) 144 | UCSR1A |= (1 << U2X1); 145 | UCSR1C = (3 << UCSZ10); // 1 stop, 8 data 146 | UCSR1B |= (1 << TXEN1); 147 | } 148 | 149 | #endif 150 | 151 | 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/m2560/makefile: -------------------------------------------------------------------------------- 1 | 2 | MCU = atmega2560 3 | F_CPU = 16000000 4 | TARGET = arduino_mega2560__m2560 5 | LWCLONE_SRC = ../../main_led.c ../../comm.c ../../led.c ../../panel.c ../../queue.c ../../clock.c 6 | 7 | include ../../default.mk 8 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/m2560/pinmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | 18 | #define LED_MAPPING_TABLE(_map_) \ 19 | \ 20 | _map_( A, 0, 0 ) /* ( AD0 ) Digital pin 22 */ \ 21 | _map_( A, 1, 0 ) /* ( AD1 ) Digital pin 23 */ \ 22 | _map_( A, 2, 0 ) /* ( AD2 ) Digital pin 24 */ \ 23 | _map_( A, 3, 0 ) /* ( AD3 ) Digital pin 25 */ \ 24 | _map_( A, 4, 0 ) /* ( AD4 ) Digital pin 26 */ \ 25 | _map_( A, 5, 0 ) /* ( AD5 ) Digital pin 27 */ \ 26 | _map_( A, 6, 0 ) /* ( AD6 ) Digital pin 28 */ \ 27 | _map_( A, 7, 0 ) /* ( AD7 ) Digital pin 29 */ \ 28 | _map_( C, 7, 0 ) /* ( A15 ) Digital pin 30 */ \ 29 | _map_( C, 6, 0 ) /* ( A14 ) Digital pin 31 */ \ 30 | _map_( C, 5, 0 ) /* ( A13 ) Digital pin 32 */ \ 31 | _map_( C, 4, 0 ) /* ( A12 ) Digital pin 33 */ \ 32 | _map_( C, 3, 0 ) /* ( A11 ) Digital pin 34 */ \ 33 | _map_( C, 2, 0 ) /* ( A10 ) Digital pin 35 */ \ 34 | _map_( C, 1, 0 ) /* ( A9 ) Digital pin 36 */ \ 35 | _map_( C, 0, 0 ) /* ( A8 ) Digital pin 37 */ \ 36 | _map_( D, 7, 0 ) /* ( T0 ) Digital pin 38 */ \ 37 | _map_( G, 2, 0 ) /* ( ALE ) Digital pin 39 */ \ 38 | _map_( G, 1, 0 ) /* ( RD ) Digital pin 40 */ \ 39 | _map_( G, 0, 0 ) /* ( WR ) Digital pin 41 */ \ 40 | _map_( L, 7, 0 ) /* Digital pin 42 */ \ 41 | _map_( L, 6, 0 ) /* Digital pin 43 */ \ 42 | _map_( L, 5, 0 ) /* ( OC5C ) Digital pin 44 (PWM) */ \ 43 | _map_( L, 4, 0 ) /* ( OC5B ) Digital pin 45 (PWM) */ \ 44 | _map_( L, 3, 0 ) /* ( OC5A ) Digital pin 46 (PWM) */ \ 45 | _map_( L, 2, 0 ) /* ( T5 ) Digital pin 47 */ \ 46 | _map_( L, 1, 0 ) /* ( ICP5 ) Digital pin 48 */ \ 47 | _map_( L, 0, 0 ) /* ( ICP4 ) Digital pin 49 */ \ 48 | _map_( B, 3, 0 ) /* ( MISO/PCINT3 ) Digital pin 50 (MISO) */ \ 49 | _map_( B, 2, 0 ) /* ( MOSI/PCINT2 ) Digital pin 51 (MOSI) */ \ 50 | _map_( B, 1, 0 ) /* ( SCK/PCINT1 ) Digital pin 52 (SCK) */ \ 51 | _map_( B, 0, 0 ) /* ( SS/PCINT0 ) Digital pin 53 (SS) */ \ 52 | \ 53 | /* end */ 54 | 55 | #if (USE_MOUSE) 56 | #define MOUSE_X_CLK_INDEX 9 57 | #define MOUSE_X_DIR_INDEX 10 58 | #define MOUSE_Y_CLK_INDEX 11 59 | #define MOUSE_Y_DIR_INDEX 12 60 | #endif 61 | 62 | #define SHIFT_SWITCH_INDEX 13 63 | 64 | #define PANEL_MAPPING_TABLE(_map_) \ 65 | \ 66 | _map_( E, 4, MOD_LeftShift, 0 ) /* ( OC3B/INT4 ) Digital pin 2 (PWM) */ \ 67 | _map_( E, 5, MOD_RightShift, 0 ) /* ( OC3C/INT5 ) Digital pin 3 (PWM) */ \ 68 | _map_( G, 5, MOD_LeftControl, 0 ) /* ( OC0B ) Digital pin 4 (PWM) */ \ 69 | _map_( E, 3, MOD_RightControl,0 ) /* ( OC3A/AIN1 ) Digital pin 5 (PWM) */ \ 70 | _map_( H, 3, KEY_Esc, 0 ) /* ( OC4A ) Digital pin 6 (PWM) */ \ 71 | _map_( H, 4, KEY_Enter, 0 ) /* ( OC4B ) Digital pin 7 (PWM) */ \ 72 | _map_( H, 5, KEY_1, KEY_P ) /* ( OC4C ) Digital pin 8 (PWM) */ \ 73 | _map_( H, 6, KEY_5, KEY_5 ) /* ( OC2B ) Digital pin 9 (PWM) */ \ 74 | _map_( B, 4, KEY_A, KEY_A ) /* ( OC2A/PCINT4 ) Digital pin 10 (PWM) */ \ 75 | _map_( B, 5, KEY_S, KEY_S ) /* ( OC1A/PCINT5 ) Digital pin 11 (PWM) */ \ 76 | _map_( B, 6, KEY_D, KEY_D ) /* ( OC1B/PCINT6 ) Digital pin 12 (PWM) */ \ 77 | _map_( B, 7, J1_Up, KEY_UpArrow ) /* ( OC0A/OC1C/PCINT7 ) Digital pin 13 (PWM) */ \ 78 | _map_( J, 1, J1_Left, KEY_LeftArrow ) /* ( TXD3/PCINT10 ) Digital pin 14 (TX3) */ \ 79 | _map_( J, 0, 0, 0 ) /* ( RXD3/PCINT9 ) Digital pin 15 (RX3) */ \ 80 | _map_( H, 1, J2_Button5, 0 ) /* ( TXD2 ) Digital pin 16 (TX2) */ \ 81 | _map_( H, 0, J2_Button4, 0 ) /* ( RXD2 ) Digital pin 17 (RX2) */ \ 82 | _map_( D, 1, J2_Button3, KM_ALT_F4 ) /* ( SDA/INT1 ) Digital pin 20 (SDA) */ \ 83 | _map_( D, 0, J2_Button2, KM_SHIFT_F7 ) /* ( SCL/INT0 ) Digital pin 21 (SCL) */ \ 84 | _map_( F, 0, J1_Right, KEY_RightArrow ) /* ( ADC0 ) Analog pin 0 */ \ 85 | _map_( F, 1, J1_Button1, KEY_Enter ) /* ( ADC1 ) Analog pin 1 */ \ 86 | _map_( F, 4, J1_Button4, 0 ) /* ( ADC4/TMK ) Analog pin 4 */ \ 87 | _map_( F, 5, J1_Button5, 0 ) /* ( ADC5/TMS ) Analog pin 5 */ \ 88 | _map_( F, 6, J2_Button1, KEY_F7 ) /* ( ADC6 ) Analog pin 6 */ \ 89 | _map_( F, 7, J2_Right, AC_VolumeUp ) /* ( ADC7 ) Analog pin 7 */ \ 90 | _map_( K, 0, J2_Left, AC_VolumeDown ) /* ( ADC8/PCINT16 ) Analog pin 8 */ \ 91 | _map_( K, 1, J2_Up, KEY_PageUp ) /* ( ADC9/PCINT17 ) Analog pin 9 */ \ 92 | _map_( K, 2, J2_Down, KEY_PageDown ) /* ( ADC10/PCINT18 ) Analog pin 10 */ \ 93 | _map_( K, 3, J1_Down, KEY_DownArrow ) /* ( ADC11/PCINT19 ) Analog pin 11 */ \ 94 | _map_( K, 4, KEY_2, AC_Mute ) /* ( ADC12/PCINT20 ) Analog pin 12 */ \ 95 | _map_( K, 5, J1_Button8, 0 ) /* ( ADC13/PCINT21 ) Analog pin 13 */ \ 96 | _map_( K, 6, J1_Button7, 0 ) /* ( ADC14/PCINT22 ) Analog pin 14 */ \ 97 | _map_( K, 7, J1_Button6, 0 ) /* ( ADC15/PCINT23 ) Analog pin 15 */ \ 98 | \ 99 | /* end */ 100 | 101 | 102 | // (port, pin, mux, value_min, value_max, joyid, axis 103 | // for mega2560, mux is 0x00..0x07 => (ADC0..ADC7) and 0x20..0x27 => (ADC8..ADC15) 104 | #define ADC_MAPPING_TABLE(_map_) \ 105 | \ 106 | _map_( F, 2, 0x02, 0.000, 1.000, ID_Joystick2, 0 ) /* Analog Pin 2 */ \ 107 | _map_( F, 3, 0x03, 0.000, 1.000, ID_Joystick2, 1 ) /* Analog Pin 3 */ \ 108 | \ 109 | /* end */ 110 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/makefile: -------------------------------------------------------------------------------- 1 | 2 | DIRS = m16u2 m2560 3 | 4 | all: 5 | for i in $(DIRS); do make --directory=$$i clean; make --directory=$$i all; done 6 | 7 | clean: 8 | for i in $(DIRS); do make --directory=$$i clean; done 9 | -------------------------------------------------------------------------------- /firmware/arduino_mega2560/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Program ATmega2560: 3 | ------------------- 4 | avrdude -c wiring -p atmega2560 -P com20 -b 115200 -v -U flash:w:m2560/arduino_mega2560__m2560.hex:i 5 | 6 | 7 | Program ATmega8u2 / ATmega16u2 8 | ------------------------------ 9 | Use the tool "Flip" from Atmel and upload "arduino_mega2560__m16u2.hex" or 10 | to revert to Arduino, upload "Arduino-usbserial-atmega16u2-Mega2560-Rev3.hex" from Arduino installation folder "arduino-root\hardware\arduino\firmwares\atmegaxxu2\arduino-usbserial" 11 | -------------------------------------------------------------------------------- /firmware/arduino_promicro/devconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DEVCONFIG_H__INCLUDED 18 | #define DEVCONFIG_H__INCLUDED 19 | 20 | 21 | /**************************************** 22 | USB device config 23 | ****************************************/ 24 | 25 | #define ENABLE_LED_DEVICE 26 | #define ENABLE_ANALOG_INPUT 27 | #define ENABLE_PANEL_DEVICE 28 | #define NUM_JOYSTICKS 2 29 | #define USE_MOUSE 1 30 | #define USE_CONSUMER 0 31 | #define USE_KEYBOARD 1 32 | 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /firmware/arduino_promicro/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #if (F_CPU != 16000000) 21 | #error "invalid CPU clock frequency ==> should be 16 MHZ" 22 | #endif 23 | 24 | #if !defined(__AVR_ATmega32U4__) 25 | #error "invalid CPU type ==> should be ATMega32u4" 26 | #endif 27 | 28 | #include "devconfig.h" 29 | #include "pinmap.h" 30 | 31 | 32 | /**************************************** 33 | LED driver config 34 | ****************************************/ 35 | 36 | #if defined(ENABLE_LED_DEVICE) 37 | 38 | #define LED_TIMER_vect TIMER0_COMPA_vect 39 | 40 | static void inline led_timer_init(void) 41 | { 42 | const int T0_CYCLE_US = 200; 43 | OCR0A = (((T0_CYCLE_US * (F_CPU / 1000L)) / (64 * 1000L)) - 1); 44 | TCCR0A = _BV(WGM01); // clear timer/counter on compare0 match 45 | TCCR0B = _BV(CS01) |_BV(CS00); // prescale 64 46 | TIMSK0 = _BV(OCIE0A); // enable Output Compare 0 overflow interrupt 47 | TCNT0 = 0x00; 48 | } 49 | 50 | #endif 51 | 52 | 53 | /**************************************** 54 | Panel config 55 | ****************************************/ 56 | 57 | #if defined(ENABLE_PANEL_DEVICE) 58 | #define PANEL_TASK 59 | #endif 60 | 61 | 62 | /**************************************** 63 | ADC config 64 | ****************************************/ 65 | 66 | #if defined(ENABLE_ANALOG_INPUT) 67 | 68 | static void inline ADC_init(void) 69 | { 70 | ADMUX = (1 << REFS0); // VCC with external capacitor on ARef pin 71 | 72 | ADCSRA = 73 | (1 << ADEN) | //enable 74 | (1 << ADSC) | //start conversion(s) 75 | (1 << ADIE) | // interrupt enable 76 | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler 128x 77 | } 78 | 79 | static void inline ADC_setmux(uint8_t mux) 80 | { 81 | ADMUX &= ~0x1F; 82 | ADMUX |= mux & 0x1F; 83 | ADCSRB &= ~(1 << MUX5); 84 | ADCSRB |= (((mux >> 5) & 0x01) << MUX5); 85 | } 86 | 87 | #endif 88 | 89 | 90 | /**************************************** 91 | Clock config 92 | ****************************************/ 93 | 94 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 95 | #define CLOCK_TCNT TCNT1 96 | #define CLOCK_OCR OCR1A 97 | 98 | static void inline clock_init(void) 99 | { 100 | OCR1A = TCNT1 + (F_CPU / 1000); 101 | TCCR1B = _BV(CS10); // normal mode, no prescale 102 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 103 | } 104 | 105 | 106 | /**************************************** 107 | Debug UART config 108 | ****************************************/ 109 | 110 | #if defined(DEBUGLEVEL) 111 | 112 | #define DEBUG_TX_UART_vect USART1_UDRE_vect 113 | 114 | static void inline debug_uart_setUDRIE(uint8_t x) { if (x) { UCSR1B |= (1 << UDRIE1); } else { UCSR1B &= ~(1 << UDRIE1); } } 115 | static void inline debug_uart_writeUDR(uint8_t x) { UDR1 = x; } 116 | 117 | static void inline debug_uart_init(void) 118 | { 119 | UBRR1 = 16; // 115200 bit/s @ 16MHz (==> 2.1% error) 120 | UCSR1A |= (1 << U2X1); 121 | UCSR1C = (3 << UCSZ10); // 1 stop, 8 data 122 | UCSR1B |= (1 << TXEN1); 123 | } 124 | 125 | #endif 126 | 127 | 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /firmware/arduino_promicro/makefile: -------------------------------------------------------------------------------- 1 | 2 | TARGET = arduino_promicro 3 | TARGET_PATH = ./arduino_promicro 4 | PARENT_PATH = ./.. 5 | MCU = atmega32u4 6 | F_CPU = 16000000 7 | LWCLONE_SRC = ../main_usb.c ../descriptors.c ../comm.c ../led.c ../panel.c ../queue.c ../clock.c 8 | 9 | include ../lufa.mk 10 | -------------------------------------------------------------------------------- /firmware/arduino_promicro/pinmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #define LED_MAPPING_TABLE(_map_) \ 18 | /* the following corresponds to the Arduino Leonardo mapping */ \ 19 | \ 20 | _map_( B, 0, 1 ) /* RX LED */ \ 21 | _map_( D, 5, 1 ) /* TX LED */ \ 22 | \ 23 | /* end */ 24 | 25 | 26 | #define MOUSE_X_CLK_INDEX 9 27 | #define MOUSE_X_DIR_INDEX 10 28 | #define MOUSE_Y_CLK_INDEX 11 29 | #define MOUSE_Y_DIR_INDEX 12 30 | #define MOUSE_X_DELTA 2 31 | #define MOUSE_Y_DELTA 2 32 | 33 | #define SHIFT_SWITCH_INDEX 13 34 | 35 | #define PANEL_MAPPING_TABLE(_map_) \ 36 | \ 37 | _map_( D, 2, KEY_Esc, 0 ) /* Digital Pin 0 */ \ 38 | _map_( D, 3, KEY_1, KEY_P ) /* Digital Pin 1 */ \ 39 | _map_( D, 1, KEY_2, AC_Mute ) /* Digital Pin 2 */ \ 40 | _map_( D, 0, KEY_5, KEY_5 ) /* Digital Pin 3 */ \ 41 | _map_( D, 4, J1_Up, KEY_UpArrow ) /* Digital Pin 4 */ \ 42 | _map_( C, 6, J1_Left, KEY_LeftArrow ) /* Digital Pin 5 */ \ 43 | _map_( D, 7, J1_Right, KEY_RightArrow ) /* Digital Pin 6 */ \ 44 | _map_( E, 6, J1_Down, KEY_DownArrow ) /* Digital Pin 7 */ \ 45 | _map_( B, 4, J1_Button1, KEY_Enter ) /* Digital Pin 8 */ \ 46 | _map_( B, 5, 0, 0 ) /* Digital Pin 9 */ \ 47 | _map_( B, 6, 0, 0 ) /* Digital Pin 10 */ \ 48 | _map_( B, 3, 0, 0 ) /* Digital Pin 14 / MISO */ \ 49 | _map_( B, 1, 0, 0 ) /* Digital Pin 15 / SCK */ \ 50 | _map_( B, 2, 0, 0 ) /* Digital Pin 16 / MOSI */ \ 51 | \ 52 | /* end */ 53 | 54 | 55 | // (port, pin, mux, value_min, value_max, joyid, axis 56 | #define ADC_MAPPING_TABLE(_map_) \ 57 | \ 58 | _map_( F, 7, 0x07, 0.000, 1.000, ID_Joystick1, 0 ) /* Analog Pin 0 */ \ 59 | _map_( F, 6, 0x06, 1.000, 0.000, ID_Joystick1, 1 ) /* Analog Pin 1 */ \ 60 | _map_( F, 5, 0x05, 0.100, 0.500, ID_Joystick2, 0 ) /* Analog Pin 2 */ \ 61 | _map_( F, 4, 0x04, 0.000, 0.500, ID_Joystick2, 1 ) /* Analog Pin 3 */ \ 62 | \ 63 | /* end */ 64 | 65 | -------------------------------------------------------------------------------- /firmware/arduino_uno/devconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DEVCONFIG_H__INCLUDED 18 | #define DEVCONFIG_H__INCLUDED 19 | 20 | 21 | /**************************************** 22 | USB device config 23 | ****************************************/ 24 | 25 | #define ENABLE_LED_DEVICE 26 | 27 | 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /firmware/arduino_uno/m328/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #include 21 | #include 22 | 23 | #if (F_CPU != 16000000) 24 | #error "invalid CPU clock frequency ==> should be 16 MHZ" 25 | #endif 26 | 27 | #if !defined(__AVR_ATmega8__) && !defined(__AVR_ATmega168__) && !defined(__AVR_ATmega328__) 28 | #error "invalid CPU type ==> should be ATMega8/168/328" 29 | #endif 30 | 31 | #include "../devconfig.h" 32 | #include "pinmap.h" 33 | 34 | 35 | /**************************************** 36 | LED driver config 37 | ****************************************/ 38 | 39 | #if defined(ENABLE_LED_DEVICE) 40 | 41 | #define LED_TIMER_vect TIMER0_COMPA_vect 42 | 43 | static void inline led_timer_init(void) 44 | { 45 | const int T0_CYCLE_US = 200; 46 | OCR0A = (((T0_CYCLE_US * (F_CPU / 1000L)) / (64 * 1000L)) - 1); 47 | TCCR0A = _BV(WGM01); // clear timer/counter on compare0 match 48 | TCCR0B = _BV(CS01) |_BV(CS00); // prescale 64 49 | TIMSK0 = _BV(OCIE0A); // enable Output Compare 0 overflow interrupt 50 | TCNT0 = 0x00; 51 | } 52 | 53 | #endif 54 | 55 | 56 | /**************************************** 57 | Panel config 58 | ****************************************/ 59 | 60 | #if defined(ENABLE_PANEL_DEVICE) 61 | #define PANEL_TASK 62 | #endif 63 | 64 | 65 | /**************************************** 66 | Data UART config 67 | ****************************************/ 68 | 69 | #define DATA_TX_UART_vect USART_UDRE_vect 70 | #define DATA_RX_UART_vect USART_RX_vect 71 | 72 | #include "../../data_uart0.h" 73 | 74 | static void inline data_uart_init(void) 75 | { 76 | UBRR0 = 3; // 250 kBit/s @ 16 MHz CPU 77 | UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00) | (1 << UPM01) | (1 << UPM00); // asynchron uart, odd parity, 9-bit-character, 1 stop bit 78 | UCSR0B |= (1 << UCSZ02) | (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0); // enable Receiver and Transmitter 79 | } 80 | 81 | 82 | /**************************************** 83 | Clock config 84 | ****************************************/ 85 | 86 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 87 | #define CLOCK_TCNT TCNT1 88 | #define CLOCK_OCR OCR1A 89 | 90 | static void inline clock_init(void) 91 | { 92 | OCR1A = TCNT1 + (F_CPU / 1000); 93 | TCCR1B = _BV(CS10); // normal mode, no prescale 94 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 95 | } 96 | 97 | 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /firmware/arduino_uno/m328/makefile: -------------------------------------------------------------------------------- 1 | 2 | MCU = atmega328 3 | F_CPU = 16000000 4 | TARGET = arduino_uno__m328 5 | LWCLONE_SRC = ../../main_led.c ../../comm.c ../../led.c ../../panel.c ../../queue.c ../../clock.c 6 | 7 | include ../../default.mk 8 | -------------------------------------------------------------------------------- /firmware/arduino_uno/m328/pinmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #define LED_MAPPING_TABLE(_map_) \ 18 | \ 19 | _map_( D, 2, 0 ) /* Digital Pin 2 */ \ 20 | _map_( D, 3, 0 ) /* Digital Pin 3 */ \ 21 | _map_( D, 4, 0 ) /* Digital Pin 4 */ \ 22 | _map_( D, 5, 0 ) /* Digital Pin 5 */ \ 23 | _map_( D, 6, 0 ) /* Digital Pin 6 */ \ 24 | _map_( D, 7, 0 ) /* Digital Pin 7 */ \ 25 | _map_( B, 0, 0 ) /* Digital Pin 8 */ \ 26 | _map_( B, 1, 0 ) /* Digital Pin 9 */ \ 27 | _map_( B, 2, 0 ) /* Digital Pin 10 */ \ 28 | _map_( B, 3, 0 ) /* Digital Pin 11 */ \ 29 | _map_( B, 4, 0 ) /* Digital Pin 12 */ \ 30 | _map_( B, 5, 0 ) /* Digital Pin 13 */ \ 31 | \ 32 | _map_( C, 0, 0 ) /* Analog Pin 0 */ \ 33 | _map_( C, 1, 0 ) /* Analog Pin 1 */ \ 34 | _map_( C, 2, 0 ) /* Analog Pin 2 */ \ 35 | _map_( C, 3, 0 ) /* Analog Pin 3 */ \ 36 | _map_( C, 4, 0 ) /* Analog Pin 4 */ \ 37 | _map_( C, 5, 0 ) /* Analog Pin 5 */ \ 38 | \ 39 | /* end */ 40 | -------------------------------------------------------------------------------- /firmware/arduino_uno/m8u2/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #if (F_CPU != 16000000) 21 | #error "invalid CPU clock frequency ==> should be 16 MHZ" 22 | #endif 23 | 24 | #if !defined(__AVR_ATmega8U2__) && !defined(__AVR_ATmega16U2__) && !defined(__AVR_ATmega32U2__) 25 | #error "invalid CPU type ==> should be atmega8u2/16u2/32u2" 26 | #endif 27 | 28 | #include 29 | #include "../devconfig.h" 30 | 31 | 32 | /**************************************** 33 | Data UART config 34 | ****************************************/ 35 | 36 | #define DATA_TX_UART_vect USART1_UDRE_vect 37 | #define DATA_RX_UART_vect USART1_RX_vect 38 | 39 | #include "../../data_uart1.h" 40 | 41 | static void inline data_uart_init(void) 42 | { 43 | UBRR1 = 3; // 250 kBit/s @ 16 MHz CPU 44 | UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10) | (1 << UPM11) | (1 << UPM10); // asynchron uart, odd parity, 9-bit-character, 1 stop bit 45 | UCSR1B |= (1 << UCSZ12) | (1 << TXEN1) | (1 << RXEN1) | (1 << RXCIE1); // enable Receiver and Transmitter 46 | } 47 | 48 | 49 | /**************************************** 50 | Clock config 51 | ****************************************/ 52 | 53 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 54 | #define CLOCK_TCNT TCNT1 55 | #define CLOCK_OCR OCR1A 56 | 57 | static void inline clock_init(void) 58 | { 59 | OCR1A = TCNT1 + (F_CPU / 1000); 60 | TCCR1B = _BV(CS10); // normal mode, no prescale 61 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 62 | } 63 | 64 | 65 | /**************************************** 66 | Bootloader shutdown config 67 | ****************************************/ 68 | 69 | #define exit_bootloader(x) exit_bootloader_optiboot(x) 70 | #include 71 | 72 | static void inline exit_bootloader_optiboot(void) 73 | { 74 | // todo 75 | } 76 | 77 | 78 | #define BOOTLOADER_SIZE 4096 79 | #define BOOTLOADER_START_ADDR ((uint8_t*)1 + FLASHEND - BOOTLOADER_SIZE) 80 | 81 | 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /firmware/arduino_uno/m8u2/makefile: -------------------------------------------------------------------------------- 1 | 2 | TARGET = arduino_uno__m8u2 3 | TARGET_PATH = ./arduino_uno/m8u2 4 | PARENT_PATH = ../.. 5 | MCU = atmega8u2 6 | F_CPU = 16000000 7 | LWCLONE_SRC = ../../main_usb.c ../../descriptors.c ../../comm.c ../../led.c ../../panel.c ../../queue.c ../../clock.c 8 | CFLAGS = -I./. 9 | 10 | include ../../lufa.mk 11 | -------------------------------------------------------------------------------- /firmware/arduino_uno/makefile: -------------------------------------------------------------------------------- 1 | 2 | DIRS = m328 m8u2 3 | 4 | all: 5 | for i in $(DIRS); do make --directory=$$i clean; make --directory=$$i all; done 6 | 7 | clean: 8 | for i in $(DIRS); do make --directory=$$i clean; done 9 | -------------------------------------------------------------------------------- /firmware/arduino_uno/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Program ATmega328p: 3 | ------------------- 4 | avrdude -c arduino -p m328p -P COM22 -v -U flash:w:m328/arduino_uno__m328.hex:i 5 | 6 | 7 | Program ATmega8u2 8 | ------------------- 9 | 10 | -------------------------------------------------------------------------------- /firmware/breakout_32u2/devconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DEVCONFIG_H__INCLUDED 18 | #define DEVCONFIG_H__INCLUDED 19 | 20 | 21 | /**************************************** 22 | USB device config 23 | ****************************************/ 24 | 25 | #define ENABLE_LED_DEVICE 26 | 27 | #define ENABLE_PANEL_DEVICE 28 | #define NUM_JOYSTICKS 2 29 | #define USE_MOUSE 0 30 | #define USE_CONSUMER 1 31 | #define USE_KEYBOARD 1 32 | 33 | 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /firmware/breakout_32u2/hwconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef HWCONFIG_H__INCLUDED 18 | #define HWCONFIG_H__INCLUDED 19 | 20 | #if ((F_CPU != 8000000) && (F_CPU != 16000000)) 21 | #error "invalid CPU clock frequency ==> should be 8 MHZ or 16 MHZ" 22 | #endif 23 | 24 | #if !defined(__AVR_ATmega32U2__) 25 | #error "invalid CPU type ==> should be ATMega32u2" 26 | #endif 27 | 28 | #include 29 | #include "devconfig.h" 30 | #include "pinmap.h" 31 | 32 | 33 | /**************************************** 34 | LED driver config 35 | ****************************************/ 36 | 37 | #if defined(ENABLE_LED_DEVICE) 38 | 39 | #define LED_TIMER_vect TIMER0_COMPA_vect 40 | 41 | static void inline led_timer_init(void) 42 | { 43 | const int T0_CYCLE_US = 200; 44 | OCR0A = (((T0_CYCLE_US * (F_CPU / 1000L)) / (64 * 1000L)) - 1); 45 | TCCR0A = _BV(WGM01); // clear timer/counter on compare0 match 46 | TCCR0B = _BV(CS01) |_BV(CS00); // prescale 64 47 | TIMSK0 = _BV(OCIE0A); // enable Output Compare 0 overflow interrupt 48 | TCNT0 = 0x00; 49 | } 50 | 51 | #endif 52 | 53 | 54 | /**************************************** 55 | Panel config 56 | ****************************************/ 57 | 58 | #if defined(ENABLE_PANEL_DEVICE) 59 | #define PANEL_TASK 60 | #endif 61 | 62 | 63 | /**************************************** 64 | Clock config 65 | ****************************************/ 66 | 67 | #define CLOCK_COMPARE_MATCH_vect TIMER1_COMPA_vect 68 | #define CLOCK_TCNT TCNT1 69 | #define CLOCK_OCR OCR1A 70 | 71 | static void inline clock_init(void) 72 | { 73 | OCR1A = TCNT1 + (F_CPU / 1000); 74 | TCCR1B = _BV(CS10); // normal mode, no prescale 75 | TIMSK1 = _BV(OCIE1A); // enable Output Compare 1 interrupt 76 | } 77 | 78 | 79 | /**************************************** 80 | Debug UART config 81 | ****************************************/ 82 | 83 | #if defined(DEBUGLEVEL) 84 | 85 | #define DEBUG_TX_UART_vect USART1_UDRE_vect 86 | 87 | static void inline debug_uart_setUDRIE(uint8_t x) { if (x) { UCSR1B |= (1 << UDRIE1); } else { UCSR1B &= ~(1 << UDRIE1); } } 88 | static void inline debug_uart_writeUDR(uint8_t x) { UDR1 = x; } 89 | 90 | static void inline debug_uart_init(void) 91 | { 92 | #if (F_CPU == 16000000) 93 | UBRR1 = 16; // 115200 bit/s @ 16MHz (==> 2.1% error) 94 | #else 95 | UBRR1 = 12; // 76800 bit/s @ 8Hz (==> 0.2% error) 96 | #endif 97 | UCSR1A |= (1 << U2X1); 98 | UCSR1C = (3 << UCSZ10); // 1 stop, 8 data 99 | UCSR1B |= (1 << TXEN1); 100 | } 101 | 102 | #endif 103 | 104 | 105 | #define BOOTLOADER_SIZE 4096 106 | #define BOOTLOADER_START_ADDR ((uint8_t*)1 + FLASHEND - BOOTLOADER_SIZE) 107 | 108 | 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /firmware/breakout_32u2/makefile: -------------------------------------------------------------------------------- 1 | 2 | TARGET = breakout_32u2 3 | TARGET_PATH = ./breakout_32u2 4 | PARENT_PATH = ./.. 5 | MCU = atmega32u2 6 | F_CPU = 8000000 7 | LWCLONE_SRC = ../main_usb.c ../descriptors.c ../comm.c ../led.c ../panel.c ../queue.c ../clock.c 8 | 9 | include ../lufa.mk 10 | -------------------------------------------------------------------------------- /firmware/breakout_32u2/pinmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #define LED_MAPPING_TABLE(_map_) \ 18 | \ 19 | _map_( B, 3, 0 ) \ 20 | _map_( B, 2, 0 ) \ 21 | _map_( B, 1, 0 ) \ 22 | _map_( D, 6, 0 ) \ 23 | _map_( D, 7, 0 ) \ 24 | _map_( B, 0, 0 ) \ 25 | \ 26 | /* end */ 27 | 28 | 29 | 30 | #define SHIFT_SWITCH_INDEX 3 31 | 32 | #define MULTIFIRE_INDEX 7 // if this key is pressed once, it will result in 'MULTIFIRE_COUNT' presses 33 | #define MULTIFIRE_COUNT 5 // usefull for coin trigger that should give more than one credit 34 | 35 | #define PANEL_MAPPING_TABLE(_map_) \ 36 | \ 37 | _map_( D, 0, KEY_1, KEY_Tab ) \ 38 | _map_( D, 1, J1_Button1, KEY_Esc ) \ 39 | _map_( D, 2, KEY_2, KEY_P ) \ 40 | _map_( D, 3, 0, 0 ) \ 41 | _map_( D, 4, 0, 0 ) \ 42 | _map_( D, 5, 0, 0 ) \ 43 | _map_( B, 6, KEY_5, KEY_5 ) \ 44 | _map_( B, 7, KEY_5, KEY_5 ) \ 45 | _map_( C, 5, J1_Button2, J1_Button2 ) \ 46 | _map_( C, 4, J1_Right, KEY_Equal ) \ 47 | _map_( C, 7, J1_Left, KEY_Minus ) \ 48 | _map_( C, 2, J1_Down, AC_VolumeDown ) \ 49 | _map_( C, 6, 0, 0 ) \ 50 | _map_( B, 5, J1_Up, AC_VolumeUp ) \ 51 | _map_( B, 4, 0, 0 ) 52 | \ 53 | /* end */ 54 | 55 | -------------------------------------------------------------------------------- /firmware/clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include "comm.h" 24 | #include "clock.h" 25 | 26 | 27 | static volatile uint16_t g_tsc_lo = 0; 28 | static volatile uint16_t g_tsc_hi = 0; 29 | static volatile uint16_t g_time_ms = 0; 30 | 31 | 32 | ISR(CLOCK_COMPARE_MATCH_vect) 33 | { 34 | #if defined(ENABLE_PROFILING) 35 | profile_start(); 36 | #endif 37 | 38 | uint16_t const t = CLOCK_TCNT; 39 | 40 | if (g_tsc_lo > t) { 41 | g_tsc_hi += 1; 42 | } 43 | 44 | g_tsc_lo = t; 45 | g_time_ms += 1; 46 | 47 | CLOCK_OCR += (F_CPU / 1000); 48 | } 49 | 50 | uint32_t clock(void) 51 | { 52 | uint16_t t_lo; 53 | uint16_t t_hi; 54 | 55 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 56 | { 57 | t_lo = g_tsc_lo; 58 | t_hi = g_tsc_hi; 59 | } 60 | 61 | uint16_t const t = CLOCK_TCNT; 62 | 63 | if (t_lo > t) { 64 | t_hi += 1; 65 | } 66 | 67 | return ((uint32_t)t_hi << 16) | t; 68 | } 69 | 70 | uint16_t clock_ms(void) 71 | { 72 | uint16_t t0; 73 | 74 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 75 | { 76 | t0 = g_time_ms; 77 | } 78 | 79 | return t0; 80 | } 81 | 82 | -------------------------------------------------------------------------------- /firmware/clock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef CLOCK_H__INCLUDED 18 | #define CLOCK_H__INCLUDED 19 | 20 | #include 21 | 22 | 23 | uint32_t clock(void); 24 | uint16_t clock_ms(void); 25 | 26 | 27 | 28 | #endif // CLOCK_H__INCLUDED 29 | 30 | -------------------------------------------------------------------------------- /firmware/comm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "clock.h" 24 | #include "comm.h" 25 | 26 | extern FILE g_stdout_uart; 27 | 28 | 29 | void comm_init(void) 30 | { 31 | #if defined(exit_bootloader) 32 | exit_bootloader(); 33 | #endif 34 | 35 | #if defined(DATA_TX_UART_vect) || defined(DATA_RX_UART_vect) 36 | data_uart_init(); 37 | #endif 38 | 39 | #if defined(DEBUG_TX_UART_vect) || defined(DEBUG_TX_SOFT_UART_vect) 40 | debug_uart_init(); 41 | stdout = &g_stdout_uart; 42 | #endif 43 | } 44 | 45 | 46 | #if defined(DEBUG_TX_UART_vect) || defined(DEBUG_TX_SOFT_UART_vect) 47 | 48 | CREATE_FIFO(g_dbgfifo, 7, 0) 49 | 50 | static int putchar_uart_txt(char c, FILE *stream); 51 | static int putchar_uart_raw(char c, FILE *stream); 52 | 53 | FILE g_stdout_uart = FDEV_SETUP_STREAM(putchar_uart_txt, NULL, _FDEV_SETUP_WRITE); 54 | 55 | static int putchar_uart_raw(char c, FILE *stream) 56 | { 57 | for (;;) 58 | { 59 | if (0 == queue_push(g_dbgfifo, c)) { 60 | break; 61 | } 62 | } 63 | 64 | debug_uart_setUDRIE(1); 65 | 66 | return 0; 67 | } 68 | 69 | static int putchar_uart_txt(char c, FILE *stream) 70 | { 71 | if (c == '\n') { 72 | putchar_uart_raw('\r', stream); 73 | } 74 | 75 | putchar_uart_raw(c, stream); 76 | 77 | return 0; 78 | } 79 | 80 | #if defined(DEBUG_TX_UART_vect) 81 | 82 | ISR(DEBUG_TX_UART_vect) 83 | { 84 | #if defined(ENABLE_PROFILING) 85 | profile_start(); 86 | #endif 87 | 88 | uint8_t x; 89 | 90 | int8_t res = queue_pop(g_dbgfifo, &x); 91 | 92 | if (res != 0) 93 | { 94 | debug_uart_setUDRIE(0); 95 | return; 96 | } 97 | 98 | debug_uart_writeUDR(x); 99 | } 100 | 101 | #elif defined(DEBUG_TX_SOFT_UART_vect) 102 | 103 | #define BAUDRATE 9600 104 | #define DURATION_TXBIT ((F_CPU/8 + (BAUDRATE/2)) / BAUDRATE) 105 | 106 | ISR(DEBUG_TX_SOFT_UART_vect) 107 | { 108 | #if defined(ENABLE_PROFILING) 109 | profile_start(); 110 | #endif 111 | 112 | OCR0A += DURATION_TXBIT; 113 | 114 | static uint8_t count = 0; 115 | static uint8_t x = 0; 116 | 117 | if (count == 0) 118 | { 119 | int8_t res = queue_pop(g_dbgfifo, &x); 120 | 121 | if (res != 0) 122 | { 123 | debug_uart_setUDRIE(0); 124 | return; 125 | } 126 | 127 | x = ~x; // invert data for Stop bit generation 128 | count = 9; // 10 bits: Start + data + Stop 129 | 130 | TCCR0A = 1 << COM0A1; // clear on next compare 131 | 132 | return; 133 | } 134 | 135 | if (count) 136 | { 137 | count--; 138 | TCCR0A = 1 << COM0A1; // clear on next compare 139 | 140 | // no start bit 141 | if (!(x & 0x01)) // test inverted data 142 | TCCR0A = (1 << COM0A1) | (1 << COM0A0); // set on next compare 143 | 144 | x >>= 1; // shift zero in from left 145 | } 146 | } 147 | 148 | #endif 149 | #endif 150 | 151 | #if defined(ENABLE_PROFILING) 152 | 153 | static volatile uint8_t s_profiling = 0; 154 | static volatile uint32_t s_t_start = 0; 155 | 156 | void profile_stop(void) 157 | { 158 | if (!s_profiling) { 159 | return; 160 | } 161 | 162 | uint32_t t_now = clock(); 163 | uint32_t duration; 164 | 165 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 166 | { 167 | duration = t_now - s_t_start; 168 | s_profiling = 0; 169 | } 170 | 171 | static uint32_t duration_total = 0; 172 | static uint32_t t_start_total = 0; 173 | 174 | if (t_start_total == 0) 175 | { 176 | t_start_total = t_now; 177 | duration_total = 0; 178 | return; 179 | } 180 | 181 | duration_total += duration; 182 | 183 | if ((t_now - t_start_total) > (((uint32_t)1 << 18) * 100)) { 184 | MsgOut("\rCPU usage: %2d%%", (uint16_t)(duration_total >> 18)); 185 | t_start_total = t_now; 186 | duration_total = 0; 187 | } 188 | } 189 | 190 | void profile_start(void) 191 | { 192 | if (!s_profiling) { 193 | s_profiling = 1; 194 | s_t_start = clock(); 195 | } 196 | } 197 | 198 | #endif 199 | 200 | 201 | void sleep_ms(uint16_t ms) 202 | { 203 | if (ms > 0) { 204 | ms = clock_ms() + ms; 205 | } 206 | 207 | for (;;) 208 | { 209 | #if defined(ENABLE_PROFILING) 210 | profile_stop(); 211 | #endif 212 | 213 | sleep_mode(); 214 | 215 | if (ms == 0) { 216 | break; 217 | } 218 | 219 | uint16_t const t_now = clock_ms(); 220 | 221 | if (((int16_t)t_now - (int16_t)ms) >= 0) { 222 | break; 223 | } 224 | } 225 | } 226 | 227 | 228 | #if defined(DATA_TX_UART_vect) 229 | 230 | CREATE_FIFO(g_txfifo, 2, 4) 231 | 232 | msg_t* msg_prepare(void) 233 | { 234 | uint8_t * const pdata = chunk_prepare(g_txfifo); 235 | 236 | if (pdata == NULL) { 237 | return NULL; 238 | } 239 | 240 | return (msg_t*)pdata; 241 | } 242 | 243 | void msg_send(void) 244 | { 245 | chunk_push(g_txfifo); 246 | uart_setUDRIE(1); 247 | } 248 | 249 | ISR(DATA_TX_UART_vect) 250 | { 251 | #if defined(ENABLE_PROFILING) 252 | profile_start(); 253 | #endif 254 | 255 | static uint8_t nbytes = 0; 256 | static uint8_t * pdata = NULL; 257 | 258 | // start new data frame? 259 | 260 | if (nbytes == 0) 261 | { 262 | pdata = chunk_peek(g_txfifo); 263 | 264 | if (pdata == NULL) 265 | { 266 | //clear UDRE interrupt 267 | uart_setUDRIE(0); 268 | return; // end of transmission 269 | } 270 | 271 | uint8_t const nlen = pdata[0]; 272 | 273 | if (nlen >= g_txfifo->chunksize) 274 | { 275 | DbgOut(DBGERROR, "ISR(TX), invalid argument nlen"); 276 | chunk_release(g_txfifo); 277 | return; 278 | } 279 | 280 | uart_setBIT8TX(1); // set 9nth bit 281 | 282 | nbytes = nlen + 1; 283 | } 284 | else 285 | { 286 | uart_setBIT8TX(0); // clear 9nth bit 287 | } 288 | 289 | // transmit byte 290 | 291 | uart_writeUDR(*pdata++); 292 | nbytes--; 293 | 294 | // advance fifo 295 | 296 | if (nbytes == 0) 297 | chunk_release(g_txfifo); 298 | } 299 | 300 | #endif 301 | 302 | 303 | #if defined(DATA_RX_UART_vect) 304 | 305 | CREATE_FIFO(g_rxfifo, 2, 4) 306 | 307 | msg_t* msg_recv(void) 308 | { 309 | uint8_t * const pdata = chunk_peek(g_rxfifo); 310 | 311 | if (pdata == NULL) { 312 | return NULL; 313 | } 314 | 315 | return (msg_t*)pdata; 316 | } 317 | 318 | void msg_release(void) 319 | { 320 | chunk_release(g_rxfifo); 321 | } 322 | 323 | ISR(DATA_RX_UART_vect) 324 | { 325 | #if defined(ENABLE_PROFILING) 326 | profile_start(); 327 | #endif 328 | 329 | static uint8_t nbytes = 0; 330 | static uint8_t * pdata = NULL; 331 | 332 | uint8_t e = uart_getError(); 333 | uint8_t s = uart_getBIT8RX(); 334 | uint8_t b = uart_readUDR(); 335 | 336 | // check error condition 337 | 338 | if (e) 339 | { 340 | #if 0 341 | if (e & (1 << FE0)) 342 | DbgOut(DBGERROR, "ISR(rx), FE0"); 343 | 344 | if (e & (1 << DOR0)) 345 | DbgOut(DBGERROR, "ISR(rx), DOR0"); 346 | 347 | if (e & (1 << UPE0)) 348 | DbgOut(DBGERROR, "ISR(rx), UPE0"); 349 | #endif 350 | 351 | nbytes = 0; 352 | return; 353 | } 354 | 355 | // sync to start of frame, i.e. bit 8 is set 356 | 357 | if (s) 358 | { 359 | if (nbytes > 0) 360 | { 361 | DbgOut(DBGERROR, "ISR(rx), nbytes > 0"); 362 | } 363 | 364 | nbytes = 0; 365 | } 366 | 367 | if (nbytes == 0) 368 | { 369 | if (!s) { 370 | DbgOut(DBGERROR, "ISR(rx), !s"); 371 | return; 372 | } 373 | 374 | if (b >= g_rxfifo->chunksize) { 375 | DbgOut(DBGERROR, "ISR(rx), message size to big"); 376 | return; 377 | } 378 | 379 | pdata = chunk_prepare(g_rxfifo); 380 | 381 | if (pdata == NULL) 382 | { 383 | DbgOut(DBGERROR, "ISR(rx), buffer full"); 384 | return; 385 | } 386 | 387 | nbytes = b + 1; 388 | } 389 | 390 | // store byte 391 | 392 | *pdata++ = b; 393 | nbytes--; 394 | 395 | // commit the message 396 | 397 | if (nbytes == 0) 398 | chunk_push(g_rxfifo); 399 | } 400 | 401 | #endif 402 | -------------------------------------------------------------------------------- /firmware/comm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef UART_H__INCLUDED 18 | #define UART_H__INCLUDED 19 | 20 | #include 21 | #include 22 | #include "queue.h" 23 | 24 | 25 | typedef struct { 26 | uint8_t nlen; 27 | uint8_t data[1]; 28 | } msg_t; 29 | 30 | 31 | void comm_init(void); 32 | 33 | #if defined(DATA_TX_UART_vect) 34 | msg_t* msg_prepare(void); 35 | void msg_send(void); 36 | #endif 37 | 38 | #if defined(DATA_RX_UART_vect) 39 | msg_t* msg_recv(void); 40 | void msg_release(void); 41 | #endif 42 | 43 | 44 | typedef enum { 45 | DBGERROR = 0, 46 | DBGLOG, 47 | DBGINFO, 48 | DBGTRACE, 49 | } debuglevel; 50 | 51 | #if defined(DEBUG_TX_UART_vect) || defined(DEBUG_TX_SOFT_UART_vect) 52 | 53 | #define DbgOut(_level_, _msg_, ...) do { \ 54 | if ((_level_) > DEBUGLEVEL) break; \ 55 | printf_P( \ 56 | ((_level_) == DBGERROR) ? PSTR("[Error] ") : \ 57 | ((_level_) == DBGLOG) ? PSTR("[Log] ") : \ 58 | ((_level_) == DBGINFO) ? PSTR("[Info] ") : \ 59 | ((_level_) == DBGTRACE) ? PSTR("[Trace] ") : PSTR("[] ")); \ 60 | printf_P(PSTR(_msg_), ##__VA_ARGS__); \ 61 | printf_P(PSTR("\n")); \ 62 | } while (0) 63 | 64 | #define MsgOut(_msg_, ...) printf_P(PSTR(_msg_), ##__VA_ARGS__) 65 | 66 | #else 67 | 68 | #define DbgOut(_level_, _msg_, ...) 69 | #define MsgOut(_msg_, ...) 70 | 71 | #endif 72 | 73 | 74 | #if defined(ENABLE_PROFILING) 75 | void profile_start(void); 76 | void profile_stop(void); 77 | #endif 78 | 79 | void sleep_ms(uint16_t ms); 80 | 81 | 82 | 83 | #endif -------------------------------------------------------------------------------- /firmware/data_uart0.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DATA_UART0_H__INCLUDED 18 | #define DATA_UART0_H__INCLUDED 19 | 20 | #include 21 | #include 22 | 23 | static void inline uart_setUDRIE(uint8_t x) { if (x) { UCSR0B |= (1 << UDRIE0); } else { UCSR0B &= ~(1 << UDRIE0); } } 24 | static void inline uart_writeUDR(uint8_t x) { UDR0 = x; } 25 | static uint8_t inline uart_readUDR(void) { return UDR0; } 26 | static void inline uart_setBIT8TX(uint8_t x) { if (x) { UCSR0B |= (1 << TXB80); } else { UCSR0B &= ~(1 << TXB80); } } 27 | static uint8_t inline uart_getBIT8RX(void) { return UCSR0B & (1 << RXB80); } 28 | static uint8_t inline uart_getSRA(void) { return UCSR0A; } 29 | static uint8_t inline uart_getError(void) { return UCSR0A & ((1 << FE0) | (1 << DOR0) | (1 << UPE0)); } 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /firmware/data_uart1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef DATA_UART1_H__INCLUDED 18 | #define DATA_UART1_H__INCLUDED 19 | 20 | #include 21 | #include 22 | 23 | static void inline uart_setUDRIE(uint8_t x) { if (x) { UCSR1B |= (1 << UDRIE1); } else { UCSR1B &= ~(1 << UDRIE1); } } 24 | static void inline uart_writeUDR(uint8_t x) { UDR1 = x; } 25 | static uint8_t inline uart_readUDR(void) { return UDR1; } 26 | static void inline uart_setBIT8TX(uint8_t x) { if (x) { UCSR1B |= (1 << TXB81); } else { UCSR1B &= ~(1 << TXB81); } } 27 | static uint8_t inline uart_getBIT8RX(void) { return UCSR1B & (1 << RXB81); } 28 | static uint8_t inline uart_getSRA(void) { return UCSR1A; } 29 | static uint8_t inline uart_getError(void) { return UCSR1A & ((1 << FE1) | (1 << DOR1) | (1 << UPE1)); } 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /firmware/default.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cithraidt/lwcloneu2/40e39ac1b384716857c1152be3767d8e6d0bd674/firmware/default.mk -------------------------------------------------------------------------------- /firmware/descriptors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /* 18 | LUFA Library 19 | Copyright (C) Dean Camera, 2012. 20 | 21 | dean [at] fourwalledcubicle [dot] com 22 | www.lufa-lib.org 23 | */ 24 | 25 | /* 26 | Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) 27 | 28 | Permission to use, copy, modify, distribute, and sell this 29 | software and its documentation for any purpose is hereby granted 30 | without fee, provided that the above copyright notice appear in 31 | all copies and that both that the copyright notice and this 32 | permission notice and warranty disclaimer appear in supporting 33 | documentation, and that the name of the author not be used in 34 | advertising or publicity pertaining to distribution of the 35 | software without specific, written prior permission. 36 | 37 | The author disclaim all warranties with regard to this 38 | software, including all implied warranties of merchantability 39 | and fitness. In no event shall the author be liable for any 40 | special, indirect or consequential damages or any damages 41 | whatsoever resulting from loss of use, data or profits, whether 42 | in an action of contract, negligence or other tortious action, 43 | arising out of or in connection with the use or performance of 44 | this software. 45 | */ 46 | 47 | #ifndef _DESCRIPTORS_H_ 48 | #define _DESCRIPTORS_H_ 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #define XYZ_TO_BCD(a,b,c) \ 55 | ((uint16_t)(((a)/10) % 10) << 12) | \ 56 | ((uint16_t)((a) % 10) << 8) | \ 57 | ((uint16_t)((b) % 10) << 4) | \ 58 | ((uint16_t)((c) % 10) << 0) 59 | 60 | #define NUMBER_TO_BCD(x) \ 61 | ((uint16_t)(((x) / 1000) % 10) << 12) | \ 62 | ((uint16_t)(((x) % 1000) / 100) << 8) | \ 63 | ((uint16_t)(((x) % 100) / 10) << 4) | \ 64 | ((uint16_t)(((x) % 10) ) << 0) 65 | 66 | #if defined(ENABLE_LED_DEVICE) 67 | #define USB_VENDOR_ID 0xFAFA 68 | #define USB_PRODUCT_ID 0x00F3 // this is used as the device identifier, 0x00F0 is '1' up to 0x00FF is '16' 69 | #else 70 | #define USB_VENDOR_ID 0x03EB // Atmel 71 | #define USB_PRODUCT_ID 0x0147 72 | #endif 73 | 74 | #define LWCLONEU2_VERSION 1 75 | 76 | 77 | /* Type Defines: */ 78 | /** Type define for the device configuration descriptor structure. This must be defined in the 79 | * application code, as the configuration descriptor contains several sub-descriptors which 80 | * vary between devices, and which describe the device's usage to the host. 81 | */ 82 | typedef struct 83 | { 84 | USB_Descriptor_Configuration_Header_t Config; 85 | USB_Descriptor_Interface_t HID_MiscInterface; 86 | USB_HID_Descriptor_HID_t HID_MiscHID; 87 | USB_Descriptor_Endpoint_t HID_MiscReportINEndpoint; 88 | #if defined(ENABLE_PANEL_DEVICE) 89 | USB_Descriptor_Interface_t HID_PanelInterface; 90 | USB_HID_Descriptor_HID_t HID_PanelHID; 91 | USB_Descriptor_Endpoint_t HID_PanelReportINEndpoint; 92 | #endif 93 | #if defined(ENABLE_LED_DEVICE) 94 | USB_Descriptor_Interface_t HID_LEDInterface; 95 | USB_HID_Descriptor_HID_t HID_LEDHID; 96 | USB_Descriptor_Endpoint_t HID_LEDReportINEndpoint; 97 | #endif 98 | } USB_Descriptor_Configuration_t; 99 | 100 | /* Macros: */ 101 | /** Endpoint address of the Panel HID reporting IN endpoint. */ 102 | #define MISC_EPADDR (ENDPOINT_DIR_IN | 1) 103 | #define PANEL_EPADDR (ENDPOINT_DIR_IN | 2) 104 | #define LED_EPADDR (ENDPOINT_DIR_IN | 3) 105 | 106 | /** Size in bytes of the Panel HID reporting IN endpoint. */ 107 | #define MISC_EPSIZE 64 108 | #define PANEL_EPSIZE 8 109 | #define LED_EPSIZE 64 110 | 111 | #define MISC_INTERVAL_MS 10 112 | #define PANEL_INTERVAL_MS 2 113 | #define LED_INTERVAL_MS 10 114 | 115 | /** Descriptor header type value, to indicate a HID class HID descriptor. */ 116 | #define DTYPE_HID 0x21 117 | 118 | /** Descriptor header type value, to indicate a HID class HID report descriptor. */ 119 | #define DTYPE_Report 0x22 120 | 121 | /* Function Prototypes: */ 122 | uint16_t CALLBACK_USB_GetDescriptor( 123 | const uint16_t wValue, 124 | const uint8_t wIndex, 125 | const void** const DescriptorAddress, 126 | uint8_t *const DescriptorMemorySpace) 127 | ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); 128 | 129 | void SetProductID(uint16_t id); 130 | 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /firmware/keydefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /* Name: hid_input.h 18 | * Project: V-USB Mame Panel 19 | * Author: Andreas Oberdorfer 20 | * Creation Date: 2009-09-19 21 | * Copyright 2009 - 2011 Andreas Oberdorfer 22 | * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) 23 | */ 24 | 25 | #ifndef KEYDEFS_H__INCLUDED 26 | #define KEYDEFS_H__INCLUDED 27 | 28 | 29 | enum KeyboardCodes 30 | { 31 | KEY_reserved = 0, 32 | KEY_errorRollOver, 33 | KEY_POSTfail, 34 | KEY_errorUndefined, 35 | KEY_A, 36 | KEY_B, 37 | KEY_C, 38 | KEY_D, 39 | KEY_E, 40 | KEY_F, 41 | KEY_G, 42 | KEY_H, 43 | KEY_I, 44 | KEY_J, 45 | KEY_K, 46 | KEY_L, 47 | KEY_M, // 0x10 48 | KEY_N, 49 | KEY_O, 50 | KEY_P, 51 | KEY_Q, 52 | KEY_R, 53 | KEY_S, 54 | KEY_T, 55 | KEY_U, 56 | KEY_V, 57 | KEY_W, 58 | KEY_X, 59 | KEY_Y, 60 | KEY_Z, 61 | KEY_1, 62 | KEY_2, 63 | KEY_3, // 0x20 64 | KEY_4, 65 | KEY_5, 66 | KEY_6, 67 | KEY_7, 68 | KEY_8, 69 | KEY_9, 70 | KEY_0, 71 | KEY_Enter, 72 | KEY_Esc, 73 | KEY_BackSpace, 74 | KEY_Tab, 75 | KEY_Space, 76 | KEY_Minus, // - (and _) 77 | KEY_Equal, // = (and +) 78 | KEY_LeftBr, // [ 79 | KEY_RightBr, // ] -- 0x30 80 | KEY_BackSlash, // \ (and |) 81 | KEY_Hash, // Non-US # and ~ 82 | KEY_Semicolon, // ; (and :) 83 | KEY_Quotation, // ' and " 84 | KEY_Tilde, // Grave accent and tilde 85 | KEY_Comma, // , (and <) 86 | KEY_Dot, // . (and >) 87 | KEY_Slash, // / (and ?) 88 | KEY_CapsLock, // capslock 89 | KEY_F1, 90 | KEY_F2, 91 | KEY_F3, 92 | KEY_F4, 93 | KEY_F5, 94 | KEY_F6, 95 | KEY_F7, // 0x40 96 | KEY_F8, 97 | KEY_F9, 98 | KEY_F10, 99 | KEY_F11, 100 | KEY_F12, 101 | KEY_PrtScr, 102 | KEY_ScrLck, 103 | KEY_Pause, 104 | KEY_Ins, 105 | KEY_Home, 106 | KEY_PageUp, 107 | KEY_Del, 108 | KEY_End, 109 | KEY_PageDown, 110 | KEY_RightArrow, 111 | KEY_LeftArrow, // 0x50 112 | KEY_DownArrow, 113 | KEY_UpArrow, 114 | KEY_NumLock, 115 | KEY_KP_Slash, 116 | KEY_KP_Ast, 117 | KEY_KP_Minus, 118 | KEY_KP_Plus, 119 | KEY_KP_Enter, 120 | KEY_KP_1, 121 | KEY_KP_2, 122 | KEY_KP_3, 123 | KEY_KP_4, 124 | KEY_KP_5, 125 | KEY_KP_6, 126 | KEY_KP_7, 127 | KEY_KP_8, // 0x60 128 | KEY_KP_9, 129 | KEY_KP_0, 130 | KEY_KP_Comma, 131 | KEY_Euro, // <|> Typically near the Left-Shift key in AT-102 implementations 132 | KEY_Application 133 | }; 134 | 135 | enum KeyModCodes 136 | { 137 | KM_ALT_F4 = 0x70, 138 | KM_SHIFT_F7 139 | }; 140 | 141 | enum ModifiersCodes 142 | { 143 | MOD_LeftControl = 0x80, 144 | MOD_LeftShift, 145 | MOD_LeftAlt, 146 | MOD_LeftGUI, 147 | MOD_RightControl, 148 | MOD_RightShift, 149 | MOD_RightAlt, 150 | MOD_RightGUI, 151 | }; 152 | #define ModifierBit(key) (1 << (key - MOD_LeftControl)) 153 | 154 | enum ConsumerCodes 155 | { 156 | AC_VolumeUp = 0x90, 157 | AC_VolumeDown, 158 | AC_Mute 159 | }; 160 | #define ConsumerBit(key) (1 << (key - AC_VolumeUp)) 161 | 162 | enum MouseButtonCodes 163 | { 164 | MB_Left = 0x98, 165 | MB_Right, 166 | MB_Middle 167 | }; 168 | #define MouseButtonBit(key) (1 << (key - MB_Left)) 169 | 170 | enum JoystickCodes 171 | { 172 | NR_OF_EVENTS_PER_JOY = 12, 173 | 174 | J1_Left = 0xA0, 175 | J1_Right, 176 | J1_Up, 177 | J1_Down, 178 | J1_Button1, 179 | J1_Button2, 180 | J1_Button3, 181 | J1_Button4, 182 | J1_Button5, 183 | J1_Button6, 184 | J1_Button7, 185 | J1_Button8, 186 | 187 | J2_Left, 188 | J2_Right, 189 | J2_Up, 190 | J2_Down, 191 | J2_Button1, 192 | J2_Button2, 193 | J2_Button3, 194 | J2_Button4, 195 | J2_Button5, 196 | J2_Button6, 197 | J2_Button7, 198 | J2_Button8, 199 | 200 | J3_Left, 201 | J3_Right, 202 | J3_Up, 203 | J3_Down, 204 | J3_Button1, 205 | J3_Button2, 206 | J3_Button3, 207 | J3_Button4, 208 | J3_Button5, 209 | J3_Button6, 210 | J3_Button7, 211 | J3_Button8, 212 | 213 | J4_Left, 214 | J4_Right, 215 | J4_Up, 216 | J4_Down, 217 | J4_Button1, 218 | J4_Button2, 219 | J4_Button3, 220 | J4_Button4, 221 | J4_Button5, 222 | J4_Button6, 223 | J4_Button7, 224 | J4_Button8, 225 | 226 | AG_Left, 227 | AG_Right, 228 | AG_Up, 229 | AG_Down, 230 | AG_Button1, 231 | AG_Button2, 232 | AG_Button3, 233 | AG_Button4, 234 | AG_Button5, 235 | AG_Button6, 236 | AG_Button7, 237 | AG_Button8 238 | }; 239 | #define JoyButtonBit(key) (0x01 << (key - J1_Button1)) 240 | 241 | 242 | 243 | #endif // KEYDEFS_H__INCLUDED 244 | -------------------------------------------------------------------------------- /firmware/led.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include "led.h" 23 | 24 | 25 | #if !defined(LED_TIMER_vect) 26 | void led_init(void) {} 27 | void led_update(uint8_t *p8bytes) {} 28 | #else 29 | 30 | 31 | #define MAP(X, pin, inv) X##pin##_index, 32 | enum { LED_MAPPING_TABLE(MAP) NUMBER_OF_LEDS }; 33 | #undef MAP 34 | 35 | #define NUMBER_OF_BANKS ((NUMBER_OF_LEDS + 7) / 8) 36 | #define MAX_PWM 49 37 | 38 | 39 | #if (NUMBER_OF_LEDS > 32) 40 | #error "number of led pins is bigger than 32!" 41 | #endif 42 | 43 | 44 | struct { 45 | volatile uint8_t enable; 46 | volatile uint8_t mode; 47 | } g_LED[NUMBER_OF_BANKS * 8]; 48 | 49 | volatile uint16_t g_dt = 256; // access is not atomic, but the read in the pwm loop is not critical 50 | 51 | 52 | static void update_state(uint8_t * p5bytes); 53 | static void update_profile(int8_t k, uint8_t * p8bytes); 54 | static void update_pwm(uint8_t *pwm, int8_t n, uint16_t t); 55 | static void led_ports_init(void); 56 | 57 | 58 | 59 | void led_init(void) 60 | { 61 | /* LED driver */ 62 | led_ports_init(); 63 | 64 | // Timer for soft-PWM 65 | led_timer_init(); 66 | } 67 | 68 | 69 | void led_update(uint8_t *p8bytes) 70 | { 71 | static uint8_t nbank = 0; 72 | 73 | if (p8bytes[0] == 64) 74 | { 75 | update_state(p8bytes + 1); 76 | nbank = 0; 77 | } 78 | else 79 | { 80 | update_profile(nbank, p8bytes); 81 | nbank = (nbank + 1) & 0x03; 82 | } 83 | } 84 | 85 | 86 | static void update_state(uint8_t * p5bytes) 87 | { 88 | for (int8_t k = 0; k < NUMBER_OF_BANKS; k++) 89 | { 90 | uint8_t b = p5bytes[k]; 91 | 92 | for (int8_t i = 0; i < 8; i++) 93 | { 94 | g_LED[k * 8 + i].enable = b & 0x01; 95 | b >>= 1; 96 | } 97 | } 98 | 99 | uint8_t pulse_speed = p5bytes[4]; 100 | 101 | if (pulse_speed > 7) 102 | pulse_speed = 7; 103 | 104 | if (pulse_speed == 0) 105 | pulse_speed = 1; 106 | 107 | g_dt = pulse_speed * 128; 108 | } 109 | 110 | 111 | static void update_profile(int8_t k, uint8_t * p8bytes) 112 | { 113 | if (k >= NUMBER_OF_BANKS) 114 | return; 115 | 116 | for (int8_t i = 0; i < 8; i++) 117 | { 118 | g_LED[k * 8 + i].mode = p8bytes[i]; 119 | } 120 | } 121 | 122 | 123 | static void update_pwm(uint8_t *pwm, int8_t n, uint16_t t) 124 | { 125 | for (int8_t i = 0; i < n; i++) 126 | { 127 | if (g_LED[i].enable == 0) 128 | { 129 | pwm[i] = 0; 130 | } 131 | else 132 | { 133 | uint8_t b = g_LED[i].mode; 134 | 135 | if ((b >= 0) && (b <= MAX_PWM)) 136 | { 137 | // constant brightness 138 | 139 | pwm[i] = b; 140 | } 141 | else if (b == 129) 142 | { 143 | // triangle 144 | 145 | uint16_t x = t >> 8; 146 | if (x & 0x80) // 128..255 147 | x = 255 - x; 148 | 149 | pwm[i] = (MAX_PWM * x) >> 7; 150 | 151 | } 152 | else if (b == 130) 153 | { 154 | // rect 155 | 156 | pwm[i] = (t & 0x8000) ? MAX_PWM : 0; 157 | } 158 | else if (b == 131) 159 | { 160 | // fall 161 | 162 | uint16_t x = 255 - (t >> 8); 163 | 164 | pwm[i] = (MAX_PWM * x) >> 8; 165 | } 166 | else if (b == 132) 167 | { 168 | // rise 169 | 170 | uint16_t x = t >> 8; 171 | 172 | pwm[i] = (MAX_PWM * x) >> 8; 173 | } 174 | else 175 | { 176 | // unexpected! 177 | 178 | pwm[i] = 0; 179 | } 180 | } 181 | } 182 | } 183 | 184 | 185 | ISR(LED_TIMER_vect) 186 | { 187 | #if defined(ENABLE_PROFILING) 188 | profile_start(); 189 | #endif 190 | 191 | static int8_t counter = 0; 192 | static uint16_t t = 0; 193 | static uint8_t pwm[NUMBER_OF_LEDS]; 194 | 195 | counter--; 196 | 197 | if (counter < 0) 198 | { 199 | // reset counter 200 | counter = MAX_PWM - 1; // pwm value of MAX_PWM should be allways 'on', 0 should be allways 'off' 201 | 202 | // increment time counter 203 | t += g_dt; 204 | 205 | // update pwm values 206 | update_pwm(pwm, sizeof(pwm) / sizeof(pwm[0]), t); 207 | } 208 | 209 | // set or clear all defined pins 210 | 211 | #define MAP(X, pin, inv) if ((pwm[X##pin##_index] > counter) == (!inv)) { PORT##X |= (1 << pin); } else { PORT##X &= ~(1 << pin); } 212 | LED_MAPPING_TABLE(MAP) 213 | #undef MAP 214 | } 215 | 216 | 217 | static void led_ports_init(void) 218 | { 219 | #define MAP(X, pin, inv) \ 220 | PORT##X &= ~(1 << pin); \ 221 | DDR##X |= (1 << pin); 222 | LED_MAPPING_TABLE(MAP) 223 | #undef MAP 224 | } 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /firmware/led.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef LWCLONE_LED_H__INCLUDED 18 | #define LWCLONE_LED_H__INCLUDED 19 | 20 | #include 21 | 22 | void led_init(void); 23 | void led_update(uint8_t *p8bytes); 24 | 25 | 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /firmware/lufa.mk: -------------------------------------------------------------------------------- 1 | 2 | # -------------------------------------- 3 | # LUFA Library 4 | # Copyright (C) Dean Camera, 2012. 5 | # 6 | # dean [at] fourwalledcubicle [dot] com 7 | # www.lufa-lib.org 8 | # 9 | # -------------------------------------- 10 | # LUFA Project Makefile. 11 | # -------------------------------------- 12 | 13 | ARCH = AVR8 14 | BOARD = USER 15 | F_USB = $(F_CPU) 16 | OPTIMIZATION = s 17 | LUFA_PATH = $(PARENT_PATH)/lufa/LUFA 18 | SRC = $(LWCLONE_SRC) $(LUFA_SRC_USB) 19 | CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -I$(TARGET_PATH) -I$(PARENT_PATH) 20 | LD_FLAGS = 21 | 22 | # Default target 23 | all: 24 | 25 | # Include LUFA build script makefiles 26 | include $(LUFA_PATH)/Build/lufa_core.mk 27 | include $(LUFA_PATH)/Build/lufa_sources.mk 28 | include $(LUFA_PATH)/Build/lufa_build.mk 29 | include $(LUFA_PATH)/Build/lufa_cppcheck.mk 30 | include $(LUFA_PATH)/Build/lufa_doxygen.mk 31 | include $(LUFA_PATH)/Build/lufa_dfu.mk 32 | include $(LUFA_PATH)/Build/lufa_hid.mk 33 | include $(LUFA_PATH)/Build/lufa_avrdude.mk 34 | include $(LUFA_PATH)/Build/lufa_atprogram.mk 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /firmware/main_led.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include "comm.h" 27 | #include "led.h" 28 | #include "panel.h" 29 | 30 | 31 | int main(void) 32 | { 33 | clock_init(); 34 | comm_init(); 35 | led_init(); 36 | panel_init(); 37 | 38 | set_sleep_mode(SLEEP_MODE_IDLE); 39 | 40 | sei(); 41 | 42 | DbgOut(DBGINFO, "main_led, enter main loop"); 43 | 44 | for (;;) 45 | { 46 | // process LED messages 47 | 48 | #if defined(LED_TIMER_vect) 49 | 50 | msg_t * const prxmsg = msg_recv(); 51 | 52 | if (prxmsg != NULL) 53 | { 54 | DbgOut(DBGINFO, "main_led, message received"); 55 | 56 | // is the message valid? 57 | 58 | if (prxmsg->nlen != 8) 59 | { 60 | DbgOut(DBGERROR, "main_led, invalid framesize"); 61 | } 62 | else 63 | { 64 | // process the data 65 | led_update(&prxmsg->data[0]); 66 | } 67 | 68 | msg_release(); 69 | 70 | continue; 71 | } 72 | 73 | #endif 74 | 75 | // process panel changes 76 | 77 | #if defined(PANEL_TASK) 78 | 79 | uint8_t * pdata = NULL; 80 | uint8_t const ndata = panel_get_report(&pdata); 81 | 82 | if (ndata > 0) 83 | { 84 | msg_t * const ptxmsg = msg_prepare(); 85 | 86 | if (ptxmsg != NULL) 87 | { 88 | memcpy(&ptxmsg->data[0], pdata, ndata); 89 | ptxmsg->nlen = ndata; 90 | msg_send(); 91 | } 92 | else 93 | { 94 | DbgOut(DBGERROR, "main_led, tx buffer overflow"); 95 | } 96 | 97 | continue; 98 | } 99 | 100 | #endif 101 | 102 | // if we are here, there was no new message and no new panel report 103 | // ==> enter idle mode 104 | 105 | sleep_ms(0); 106 | } 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /firmware/main_usb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include "descriptors.h" 29 | 30 | #include 31 | #include "comm.h" 32 | #include "led.h" 33 | #include "panel.h" 34 | 35 | 36 | #define LWCCONFIG_CMD_SETID 65 37 | #define LWCCONFIG_CMD_DFU 66 38 | 39 | #define LWC_CONFIG_IDENTIFIER 0xA62817B2 // some magic number(s) 40 | #define RESETSTATE_BOOTLOADER 0x42B8217C 41 | 42 | #define OFFSET_OF(_struct_, _member_) (((uint8_t*)&(((_struct_*)NULL)->_member_)) - (uint8_t*)NULL) 43 | 44 | 45 | uint32_t g_resetstate __attribute__ ((section (".noinit"))); 46 | 47 | typedef struct { 48 | uint32_t id; 49 | uint8_t ledwiz_id; 50 | uint8_t reserved[7]; 51 | } lwc_config_t; 52 | 53 | static struct { 54 | uint8_t reserved[16]; 55 | uint8_t configdata[sizeof(lwc_config_t)]; 56 | } g_eeprom_table EEMEM; 57 | 58 | 59 | static void hardware_init(void); 60 | static void main_task(void); 61 | static uint8_t* buffer_lock(void); 62 | static void buffer_unlock(void); 63 | static void hardware_restart(bool enter_bootloader); 64 | static void configure_device(void); 65 | 66 | 67 | // Main program entry point. This routine configures the hardware required by the application, then 68 | // enters a loop to run the application tasks in sequence. 69 | 70 | int main(void) 71 | { 72 | hardware_init(); 73 | USB_Init(); 74 | 75 | sei(); 76 | 77 | DbgOut(DBGINFO, "enter main loop"); 78 | 79 | do { 80 | USB_USBTask(); 81 | } while (USB_DeviceState != DEVICE_STATE_Configured); 82 | 83 | for (;;) 84 | { 85 | USB_USBTask(); 86 | main_task(); 87 | sleep_ms(0); 88 | } 89 | } 90 | 91 | 92 | static void hardware_init(void) 93 | { 94 | uint8_t const mcusr = MCUSR; // save status register 95 | 96 | // Disable watchdog if enabled by bootloader/fuses 97 | MCUSR &= ~(1 << WDRF); 98 | wdt_disable(); 99 | 100 | #if defined(BOOTLOADER_START_ADDR) 101 | // if that was a reset due to watchdog timeout that we issued, call the bootloader 102 | if ((mcusr & (1 << WDRF)) && 103 | (g_resetstate == RESETSTATE_BOOTLOADER)) 104 | { 105 | g_resetstate = 0; 106 | void (*bootloader)(void) = (void*)(BOOTLOADER_START_ADDR); 107 | bootloader(); 108 | } 109 | #endif 110 | 111 | // Disable clock division 112 | clock_prescale_set(clock_div_1); 113 | 114 | set_sleep_mode(SLEEP_MODE_IDLE); 115 | 116 | // initialize LED driver and UART and panel 117 | clock_init(); 118 | comm_init(); 119 | led_init(); 120 | panel_init(); 121 | 122 | // config 123 | configure_device(); 124 | } 125 | 126 | 127 | // load current configuration from eeprom and set USB product ID 128 | 129 | static void configure_device(void) 130 | { 131 | lwc_config_t cfg; 132 | eeprom_read_block((void*)&cfg, g_eeprom_table.configdata, sizeof(cfg)); 133 | 134 | if (cfg.id != LWC_CONFIG_IDENTIFIER) 135 | { 136 | memset(&cfg, 0x00, sizeof(cfg)); 137 | cfg.id = LWC_CONFIG_IDENTIFIER; 138 | cfg.ledwiz_id = USB_PRODUCT_ID & 0x0F; 139 | 140 | eeprom_write_block((void*)&cfg, g_eeprom_table.configdata, sizeof(cfg)); 141 | } 142 | 143 | // set USB product ID 144 | uint16_t const product_id = (USB_PRODUCT_ID & ~0x000F) | (cfg.ledwiz_id & 0x0F); 145 | SetProductID(product_id); 146 | } 147 | 148 | 149 | static void main_task(void) 150 | { 151 | #if defined(ENABLE_PANEL_DEVICE) 152 | 153 | /* Select the Joystick Report Endpoint */ 154 | Endpoint_SelectEndpoint(PANEL_EPADDR); 155 | 156 | /* Check to see if the host is ready for another packet */ 157 | if (!Endpoint_IsINReady()) 158 | return; 159 | 160 | #if defined(DATA_RX_UART_vect) 161 | 162 | msg_t * const pmsg = msg_recv(); 163 | 164 | if (pmsg != NULL) 165 | { 166 | DbgOut(DBGINFO, "main_usb, message received"); 167 | 168 | // is the message valid? 169 | 170 | if (pmsg->nlen < 2 || pmsg->nlen > 8) 171 | { 172 | DbgOut(DBGERROR, "main_usb, invalid framesize"); 173 | } 174 | else 175 | { 176 | /* Write Joystick Report Data */ 177 | Endpoint_Write_Stream_LE(&pmsg->data[0], pmsg->nlen, NULL); 178 | 179 | /* Finalize the stream transfer to send the last packet */ 180 | Endpoint_ClearIN(); 181 | } 182 | 183 | msg_release(); 184 | } 185 | 186 | #elif defined(PANEL_TASK) 187 | 188 | uint8_t * pdata; 189 | uint8_t const ndata = panel_get_report(&pdata); 190 | 191 | if (ndata > 0) 192 | { 193 | /* Write Joystick Report Data */ 194 | Endpoint_Write_Stream_LE(pdata, ndata, NULL); 195 | 196 | /* Finalize the stream transfer to send the last packet */ 197 | Endpoint_ClearIN(); 198 | } 199 | 200 | #else 201 | 202 | #error "invalid configuration, panel is enabled but no uart-rx-ISR or panel-timer-ISR" 203 | 204 | #endif 205 | 206 | #endif 207 | } 208 | 209 | 210 | // Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and 211 | // starts the library USB task to begin the enumeration and USB management process. 212 | 213 | void EVENT_USB_Device_Connect(void) 214 | { 215 | } 216 | 217 | // Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via 218 | // the status LEDs and stops the USB management and joystick reporting tasks. 219 | 220 | void EVENT_USB_Device_Disconnect(void) 221 | { 222 | } 223 | 224 | // Event handler for the library USB Configuration Changed event. 225 | 226 | void EVENT_USB_Device_ConfigurationChanged(void) 227 | { 228 | // Setup HID Report Endpoint 229 | 230 | Endpoint_ConfigureEndpoint(MISC_EPADDR, EP_TYPE_INTERRUPT, MISC_EPSIZE, 1); 231 | #if defined(ENABLE_LED_DEVICE) 232 | Endpoint_ConfigureEndpoint(LED_EPADDR, EP_TYPE_INTERRUPT, LED_EPSIZE, 1); 233 | #endif 234 | #if defined(ENABLE_PANEL_DEVICE) 235 | Endpoint_ConfigureEndpoint(PANEL_EPADDR, EP_TYPE_INTERRUPT, PANEL_EPSIZE, 1); 236 | #endif 237 | } 238 | 239 | // Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to 240 | // the device from the USB host before passing along unhandled control requests to the library for processing 241 | // internally. 242 | 243 | void EVENT_USB_Device_ControlRequest(void) 244 | { 245 | // Handle HID Class specific requests 246 | switch (USB_ControlRequest.bRequest) 247 | { 248 | case HID_REQ_GetReport: 249 | if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) 250 | { 251 | Endpoint_ClearSETUP(); 252 | 253 | uint8_t zero = 0; 254 | 255 | // Write one 'zero' byte report data to the control endpoint 256 | Endpoint_Write_Control_Stream_LE(&zero, 1); 257 | Endpoint_ClearOUT(); 258 | } 259 | break; 260 | 261 | #if defined(ENABLE_LED_DEVICE) 262 | case HID_REQ_SetReport: 263 | if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) 264 | { 265 | Endpoint_ClearSETUP(); 266 | 267 | DbgOut(DBGINFO, "HID_REQ_SetReport, bRequest: 0x%02X, wIndex: %d, wLength: %d, wValue: %d", 268 | USB_ControlRequest.bRequest, USB_ControlRequest.wIndex, USB_ControlRequest.wLength, USB_ControlRequest.wValue); 269 | 270 | uint8_t * const pdata = buffer_lock(); 271 | 272 | if (pdata != NULL) 273 | { 274 | // Read the report data from the control endpoint 275 | Endpoint_Read_Control_Stream_LE(pdata, 8); 276 | 277 | DbgOut(DBGINFO, "HID_REQ_SetReport: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 278 | pdata[0], pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]); 279 | 280 | // if this is a special command to set the ledwiz ID, execute it 281 | if (pdata[0] == LWCCONFIG_CMD_SETID) 282 | { 283 | const uint8_t id = pdata[1]; 284 | const uint8_t check = ~id; 285 | 286 | if (pdata[2] == 0xFF && 287 | pdata[3] == 0xFF && 288 | pdata[4] == 0xFF && 289 | pdata[5] == 0xFF && 290 | pdata[6] == 0xFF && 291 | pdata[7] == check) 292 | { 293 | eeprom_update_byte( 294 | &g_eeprom_table.configdata[0] + OFFSET_OF(lwc_config_t, ledwiz_id), 295 | id & 0x0F); 296 | 297 | hardware_restart(false); 298 | } 299 | } 300 | 301 | buffer_unlock(); 302 | } 303 | else 304 | { 305 | uint8_t temp[8]; 306 | Endpoint_Read_Control_Stream_LE(temp, 8); // drop data 307 | 308 | DbgOut(DBGERROR, "HID_REQ_SetReport: buffer overflow"); 309 | } 310 | 311 | Endpoint_ClearIN(); 312 | } 313 | break; 314 | #endif 315 | } 316 | } 317 | 318 | 319 | static void hardware_restart(bool enter_bootloader) 320 | { 321 | // detach from the bus 322 | USB_Disable(); 323 | USB_Detach(); 324 | 325 | // Disable all interrupts 326 | cli(); 327 | 328 | // Wait some time for the USB detachment to register on the host 329 | _delay_ms(250); 330 | 331 | // force a reset via watchdog timeout 332 | wdt_enable(WDTO_15MS); 333 | 334 | // set persistant variable, so we know that we issued the reset 335 | g_resetstate = enter_bootloader ? RESETSTATE_BOOTLOADER : 0; 336 | 337 | for (;;) {;} 338 | } 339 | 340 | 341 | #if defined(LED_TIMER_vect) 342 | 343 | static uint8_t g_databuffer[8]; 344 | 345 | static uint8_t * buffer_lock(void) 346 | { 347 | return &g_databuffer[0]; 348 | } 349 | 350 | void buffer_unlock(void) 351 | { 352 | led_update(&g_databuffer[0]); 353 | } 354 | 355 | #endif 356 | 357 | 358 | #if defined(DATA_TX_UART_vect) 359 | 360 | static uint8_t * buffer_lock(void) 361 | { 362 | msg_t * const pmsg = msg_prepare(); 363 | 364 | if (pmsg == NULL) { 365 | return NULL; 366 | } 367 | 368 | pmsg->nlen = 8; 369 | 370 | return &pmsg->data[0]; 371 | } 372 | 373 | static void buffer_unlock(void) 374 | { 375 | msg_send(); 376 | } 377 | 378 | #endif 379 | -------------------------------------------------------------------------------- /firmware/makefile: -------------------------------------------------------------------------------- 1 | 2 | DIRS = arduino_mega2560 arduino_leonardo arduino_uno breakout_32u2 arduino_promicro 3 | 4 | all: 5 | for i in $(DIRS); do make --directory=$$i clean; make --directory=$$i all; done 6 | 7 | clean: 8 | for i in $(DIRS); do make --directory=$$i clean; done 9 | -------------------------------------------------------------------------------- /firmware/panel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /* Name: hid_input.c 18 | * Project: V-USB Mame Panel 19 | * Author: Andreas Oberdorfer 20 | * Creation Date: 2009-09-19 21 | * Copyright 2009 - 2011 Andreas Oberdorfer 22 | * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include "panel.h" 34 | #include "comm.h" 35 | #include "keydefs.h" 36 | #include "clock.h" 37 | 38 | 39 | #if !defined(PANEL_TASK) 40 | void panel_init(void) {} 41 | uint8_t panel_get_report(uint8_t **ppdata) { return 0; } 42 | #else 43 | 44 | 45 | const int DEBOUNCE = 5; 46 | 47 | // derive the number of inputs from the table, let the compiler check that no pin is used twice 48 | enum { 49 | #define MAP(port, pin, normal_id, shift_id) port##pin##_index, 50 | PANEL_MAPPING_TABLE(MAP) 51 | NUMBER_OF_INPUTS, 52 | #undef MAP 53 | #if defined(LED_MAPPING_TABLE) 54 | #define MAP(port, pin, inv) port##pin##_index, 55 | LED_MAPPING_TABLE(MAP) 56 | #undef MAP 57 | #endif 58 | #if defined(ADC_MAPPING_TABLE) 59 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) port##pin##_index, 60 | ADC_MAPPING_TABLE(MAP) 61 | #undef MAP 62 | #endif 63 | }; 64 | 65 | #if defined(ADC_MAPPING_TABLE) 66 | enum { 67 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) port##pin##_adcindex, 68 | ADC_MAPPING_TABLE(MAP) 69 | #undef MAP 70 | NUM_ADC_CHANNELS 71 | }; 72 | #endif 73 | 74 | static uint8_t ReportBuffer[8]; 75 | static uint8_t InputState[NUMBER_OF_INPUTS]; 76 | static uint8_t shift_key = 0; 77 | static uint8_t shift_key_cleanup = 0; 78 | static uint8_t need_key_update = 0; 79 | static uint8_t need_consumer_update = 0; 80 | 81 | #if (NUM_JOYSTICKS >= 1) 82 | static uint8_t need_joystick_update[NUM_JOYSTICKS]; 83 | #endif 84 | 85 | #if (USE_ACCELGYRO) 86 | static uint8_t need_accelgyro_update = 0; 87 | #endif 88 | 89 | #if (USE_MOUSE != 0) 90 | static uint8_t need_mouse_update = 0; 91 | static uint8_t mouse_x_last_clk_state = 0; 92 | static uint8_t mouse_x_last_dir_state = 0; 93 | static int8_t mouse_x_count = 0; 94 | static uint8_t mouse_y_last_clk_state = 0; 95 | static uint8_t mouse_y_last_dir_state = 0; 96 | static int8_t mouse_y_count = 0; 97 | #if !defined(MOUSE_X_DELTA) 98 | #define MOUSE_X_DELTA 1 99 | #endif 100 | #if !defined(MOUSE_Y_DELTA) 101 | #define MOUSE_Y_DELTA 1 102 | #endif 103 | #endif 104 | 105 | #if defined(ENABLE_ANALOG_INPUT) 106 | static uint16_t adc_values[NUM_ADC_CHANNELS] = {0}; 107 | static const uint8_t adc_mux_table[NUM_ADC_CHANNELS] = { 108 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) mux, 109 | ADC_MAPPING_TABLE(MAP) 110 | #undef MAP 111 | }; 112 | #endif 113 | 114 | 115 | // Shift switch off 116 | PROGMEM const uint8_t NormalMapping[NUMBER_OF_INPUTS] = 117 | { 118 | #define MAP(port, pin, normal_id, shift_id) normal_id, 119 | PANEL_MAPPING_TABLE(MAP) 120 | #undef MAP 121 | }; 122 | 123 | // Shift switch on 124 | PROGMEM const uint8_t ShiftMapping[NUMBER_OF_INPUTS] = 125 | { 126 | #define MAP(port, pin, normal_id, shift_id) shift_id, 127 | PANEL_MAPPING_TABLE(MAP) 128 | #undef MAP 129 | }; 130 | 131 | 132 | #define IsKeyDown(index) (InputState[index] & 0x80) 133 | 134 | static uint8_t GetKeyNormalMap(unsigned char index) { return (index < NUMBER_OF_INPUTS) ? pgm_read_byte(NormalMapping + index) : 0; } 135 | static uint8_t GetKeyShiftMap(unsigned char index) { return (index < NUMBER_OF_INPUTS) ? pgm_read_byte(ShiftMapping + index): 0; } 136 | static uint8_t IsKeyboardCode(uint8_t key) { return (key >= KEY_A) && (key <= MOD_RightGUI); } 137 | static uint8_t IsModifierCode(uint8_t key) { return (key >= MOD_LeftControl) && (key <= MOD_RightGUI); } 138 | static uint8_t IsConsumerCode(uint8_t key) { return (key >= AC_VolumeUp) && (key <= AC_Mute); } 139 | static uint8_t GetKey(uint8_t index) { return (shift_key != 0) ? GetKeyShiftMap(index) : GetKeyNormalMap(index); } 140 | 141 | 142 | #if (NUM_JOYSTICKS >= 1) 143 | 144 | static uint8_t IsJoystickCode(uint8_t key, uint8_t joy) 145 | { 146 | key -= (joy * NR_OF_EVENTS_PER_JOY); 147 | 148 | return (key >= J1_Left) && (key < (J1_Left + NR_OF_EVENTS_PER_JOY)); 149 | } 150 | 151 | static uint8_t NeedJoystickUpdate(void) 152 | { 153 | uint8_t i; 154 | 155 | for (i = 0; i < NUM_JOYSTICKS; i++) 156 | { 157 | if (need_joystick_update[i]) { 158 | return 1; 159 | } 160 | } 161 | 162 | return 0; 163 | } 164 | 165 | #endif 166 | 167 | #if (USE_ACCELGYRO) 168 | 169 | static uint8_t IsAccelGyroCode(uint8_t key) 170 | { 171 | key -= (4 * NR_OF_EVENTS_PER_JOY); 172 | 173 | return (key >= J1_Left) && (key < (J1_Left + NR_OF_EVENTS_PER_JOY)); 174 | } 175 | 176 | #endif 177 | 178 | #if (USE_MOUSE != 0) 179 | 180 | static uint8_t IsMouseButtonCode(uint8_t key) 181 | { 182 | return (key >= MB_Left) && (key <= MB_Middle); 183 | } 184 | 185 | static void MouseMoveX(uint8_t direction) 186 | { 187 | if (direction) 188 | { 189 | if (mouse_x_count > -(127 - MOUSE_X_DELTA)) { 190 | mouse_x_count -= MOUSE_X_DELTA; 191 | } 192 | } 193 | else 194 | { 195 | if (mouse_x_count < (127 - MOUSE_X_DELTA)) { 196 | mouse_x_count += MOUSE_X_DELTA; 197 | } 198 | } 199 | 200 | need_mouse_update = 1; 201 | } 202 | 203 | static void MouseMoveY(uint8_t direction) 204 | { 205 | if (direction) 206 | { 207 | if (mouse_y_count > -(127 - MOUSE_Y_DELTA)) { 208 | mouse_y_count -= MOUSE_Y_DELTA; 209 | } 210 | } 211 | else 212 | { 213 | if (mouse_y_count < (127 - MOUSE_Y_DELTA)) { 214 | mouse_y_count += MOUSE_Y_DELTA; 215 | } 216 | } 217 | 218 | need_mouse_update = 1; 219 | } 220 | 221 | static void CheckMouseUpdate(void) 222 | { 223 | #if defined(MOUSE_X_CLK_INDEX) && defined(MOUSE_X_DIR_INDEX) 224 | 225 | uint8_t mouse_clk_state = InputState[MOUSE_X_CLK_INDEX]; 226 | uint8_t mouse_dir_state = InputState[MOUSE_X_DIR_INDEX]; 227 | 228 | if (mouse_clk_state != mouse_x_last_clk_state) 229 | { 230 | if (mouse_dir_state == mouse_x_last_dir_state) { 231 | MouseMoveX(mouse_clk_state ^ mouse_dir_state); 232 | } 233 | 234 | mouse_x_last_clk_state = mouse_clk_state; 235 | } 236 | 237 | if (mouse_dir_state != mouse_x_last_dir_state) 238 | { 239 | if (mouse_clk_state == mouse_x_last_clk_state) { 240 | MouseMoveX(!(mouse_clk_state ^ mouse_dir_state)); 241 | } 242 | 243 | mouse_x_last_dir_state = mouse_dir_state; 244 | } 245 | 246 | #endif 247 | 248 | #if defined(MOUSE_Y_CLK_INDEX) && defined(MOUSE_Y_DIR_INDEX) 249 | 250 | mouse_clk_state = InputState[MOUSE_Y_CLK_INDEX]; 251 | mouse_dir_state = InputState[MOUSE_Y_DIR_INDEX]; 252 | 253 | if (mouse_clk_state != mouse_y_last_clk_state) 254 | { 255 | if (mouse_dir_state == mouse_y_last_dir_state) { 256 | MouseMoveY(mouse_clk_state ^ mouse_dir_state); 257 | } 258 | 259 | mouse_y_last_clk_state = mouse_clk_state; 260 | } 261 | 262 | if (mouse_dir_state != mouse_y_last_dir_state) 263 | { 264 | if (mouse_clk_state == mouse_y_last_clk_state) { 265 | MouseMoveY(!(mouse_clk_state ^ mouse_dir_state)); 266 | } 267 | 268 | mouse_y_last_dir_state = mouse_dir_state; 269 | } 270 | 271 | #endif 272 | } 273 | 274 | static uint8_t NeedMouseUpdate(void) { return need_mouse_update; } 275 | 276 | #endif 277 | 278 | void panel_init(void) 279 | { 280 | #if (NUM_JOYSTICKS >= 1) 281 | memset(&need_joystick_update[0], 0x00, sizeof(need_joystick_update)); 282 | #endif 283 | 284 | #define MAP(port, pin, normal_id, shift_id) \ 285 | PORT##port |= (1 << pin); \ 286 | DDR##port &= ~(1 << pin); 287 | PANEL_MAPPING_TABLE(MAP) 288 | #undef MAP 289 | 290 | #if defined(ENABLE_ANALOG_INPUT) && defined(ADC_MAPPING_TABLE) 291 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) \ 292 | PORT##port &= ~(1 << pin); \ 293 | DDR##port &= ~(1 << pin); 294 | ADC_MAPPING_TABLE(MAP) 295 | #undef MAP 296 | 297 | ADC_init(); 298 | #endif 299 | }; 300 | 301 | static void SetNeedUpdate(uint8_t index) 302 | { 303 | uint8_t key = GetKey(index); 304 | 305 | if (IsConsumerCode(key)) 306 | { 307 | need_consumer_update = 1; 308 | return; 309 | } 310 | 311 | if (IsKeyboardCode(key)) 312 | { 313 | need_key_update = 1; 314 | return; 315 | } 316 | 317 | #if (USE_MOUSE != 0) 318 | if (IsMouseButtonCode(key)) 319 | { 320 | need_mouse_update = 1; 321 | return; 322 | } 323 | #endif 324 | 325 | #if (NUM_JOYSTICKS >= 1) 326 | { 327 | uint8_t i; 328 | 329 | for (i = 0; i < NUM_JOYSTICKS; i++) 330 | { 331 | if (IsJoystickCode(key, i)) 332 | { 333 | need_joystick_update[i] = 1; 334 | return; 335 | } 336 | } 337 | } 338 | #endif 339 | 340 | #if (USE_ACCELGYRO) 341 | if (IsAccelGyroCode(key)) 342 | { 343 | need_accelgyro_update = 1; 344 | return; 345 | } 346 | #endif 347 | } 348 | 349 | #if defined(SHIFT_SWITCH_INDEX) 350 | 351 | static void ShiftKeyCleanUp(void) 352 | { 353 | if (shift_key_cleanup == 1) 354 | { 355 | uint8_t i; 356 | shift_key_cleanup = 2; 357 | 358 | for (i = 0; i < NUMBER_OF_INPUTS; i++) 359 | { 360 | if (i != SHIFT_SWITCH_INDEX) 361 | { 362 | if (InputState[i] != 0) 363 | { 364 | if (GetKeyNormalMap(i) != GetKeyShiftMap(i)) 365 | { 366 | SetNeedUpdate(i); 367 | InputState[i] = 0; 368 | } 369 | } 370 | } 371 | } 372 | } 373 | 374 | if (shift_key_cleanup == 2) 375 | { 376 | bool no_update = !need_consumer_update && !need_key_update; 377 | 378 | #if (USE_MOUSE != 0) 379 | no_update = no_update && !NeedMouseUpdate(); 380 | #endif 381 | 382 | #if (NUM_JOYSTICKS >= 1) 383 | no_update = no_update && !NeedJoystickUpdate(); 384 | #endif 385 | 386 | #if (USE_ACCELGYRO) 387 | no_update = no_update && !need_accelgyro_update; 388 | #endif 389 | 390 | if (no_update) 391 | { 392 | shift_key_cleanup = 0; 393 | shift_key = IsKeyDown(SHIFT_SWITCH_INDEX); 394 | } 395 | } 396 | } 397 | 398 | #endif 399 | 400 | static uint8_t NeedUpdate(void) 401 | { 402 | #if defined(SHIFT_SWITCH_INDEX) 403 | ShiftKeyCleanUp(); 404 | #endif 405 | 406 | #if (USE_MOUSE != 0) 407 | if (NeedMouseUpdate()) 408 | { 409 | need_mouse_update = 0; 410 | return ID_Mouse; 411 | } 412 | #endif 413 | 414 | if (need_key_update) 415 | { 416 | need_key_update = 0; 417 | return ID_Keyboard; 418 | } 419 | 420 | if (need_consumer_update) 421 | { 422 | need_consumer_update = 0; 423 | return ID_Consumer; 424 | } 425 | 426 | uint8_t analog_update[NUM_JOYSTICKS + 1] = {0}; 427 | static uint8_t analog_counter[NUM_JOYSTICKS + 1]; 428 | 429 | #if (NUM_JOYSTICKS >= 1) 430 | for (uint8_t i = 0; i < NUM_JOYSTICKS; i++) 431 | { 432 | if (analog_counter[i] < 0xFF && need_joystick_update[i]) 433 | analog_counter[i] += 1; 434 | } 435 | #endif 436 | 437 | #if (USE_ACCELGYRO) 438 | if (analog_counter[NUM_JOYSTICKS] < 0xFF && need_accelgyro_update) 439 | analog_counter[NUM_JOYSTICKS] += 1; 440 | #endif 441 | 442 | #if defined(ENABLE_ANALOG_INPUT) && defined(ADC_MAPPING_TABLE) 443 | 444 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) \ 445 | if (joyid >= ID_Joystick1 && (joyid - ID_Joystick1) < NUM_JOYSTICKS) { analog_update[joyid - ID_Joystick1] = 1; } else \ 446 | if (joyid == ID_AccelGyro) { analog_update[NUM_JOYSTICKS] = 1; } 447 | ADC_MAPPING_TABLE(MAP) 448 | #undef MAP 449 | 450 | for (uint8_t i = 0; i < sizeof(analog_update) / sizeof(analog_update[0]); i++) 451 | { 452 | if (analog_counter[i] < 0xFF && analog_update[i] > 0) 453 | analog_counter[i] += 1; 454 | } 455 | 456 | #endif 457 | 458 | uint8_t ac_max = 0; 459 | int8_t index_max = -1; 460 | 461 | for (int8_t i = 0; i < sizeof(analog_update) / sizeof(analog_update[0]); i++) 462 | { 463 | if (ac_max < analog_counter[i]) 464 | { 465 | ac_max = analog_counter[i]; 466 | index_max = i; 467 | } 468 | } 469 | 470 | if (index_max >= 0) 471 | { 472 | analog_counter[index_max] = 0; 473 | 474 | #if (NUM_JOYSTICKS >= 1) 475 | if (index_max < NUM_JOYSTICKS) { 476 | need_joystick_update[index_max] = 0; 477 | return index_max + ID_Joystick1; 478 | } 479 | #endif 480 | 481 | #if (USE_ACCELGYRO) 482 | need_accelgyro_update = 0; 483 | return ID_AccelGyro; 484 | #endif 485 | } 486 | 487 | return ID_Unknown; 488 | } 489 | 490 | static void SetInputCount(uint8_t index, uint8_t condition) 491 | { 492 | #if (USE_MOUSE != 0) && defined(MOUSE_X_CLK_INDEX) && defined(MOUSE_X_DIR_INDEX) 493 | if ((index == MOUSE_X_CLK_INDEX) || (index == MOUSE_X_DIR_INDEX)) 494 | { 495 | InputState[index] = condition; 496 | return; 497 | } 498 | #endif 499 | 500 | #if (USE_MOUSE != 0) && defined(MOUSE_Y_CLK_INDEX) && defined(MOUSE_Y_DIR_INDEX) 501 | if ((index == MOUSE_Y_CLK_INDEX) || (index == MOUSE_Y_DIR_INDEX)) 502 | { 503 | InputState[index] = condition; 504 | return; 505 | } 506 | #endif 507 | 508 | if (index >= NUMBER_OF_INPUTS) 509 | { 510 | return; 511 | } 512 | 513 | #if defined(MULTIFIRE_INDEX) 514 | if (index == MULTIFIRE_INDEX) 515 | { 516 | static uint16_t ncycle = 0; 517 | static uint8_t ncount = 0; 518 | static uint8_t ndelay = 0; 519 | 520 | // simple debounce 521 | if (ndelay == 0 && condition) 522 | { 523 | ndelay = (100 / (DELTA_TIME_PANEL_REPORT_MS + 1)); 524 | ncount += MULTIFIRE_COUNT; 525 | } 526 | else if (ndelay > 1) 527 | { 528 | ndelay--; 529 | } 530 | else if (ndelay == 1) 531 | { 532 | if (!condition) 533 | ndelay = 0; 534 | } 535 | 536 | condition = 0; 537 | 538 | // state machine to generate multiple events 539 | if (ncount > 0) 540 | { 541 | condition = (ncycle < (100 / (DELTA_TIME_PANEL_REPORT_MS + 1))) ? 1 : 0; 542 | 543 | if (ncycle >= (600 / (DELTA_TIME_PANEL_REPORT_MS + 1))) 544 | { 545 | ncycle = 0; 546 | ncount -= 1; 547 | } 548 | else 549 | { 550 | ncycle += 1; 551 | } 552 | } 553 | } 554 | #endif 555 | 556 | uint8_t changed = 0; 557 | uint8_t count = InputState[index]; 558 | uint8_t state = count & 0x80; 559 | count &= 0x7f; 560 | 561 | if (condition) 562 | { 563 | if (count <= DEBOUNCE) 564 | { 565 | if ((count == DEBOUNCE) && !state) 566 | { 567 | changed = 1; 568 | state = 0x80; 569 | } 570 | 571 | count++; 572 | } 573 | else 574 | { 575 | return; 576 | } 577 | } 578 | else 579 | { 580 | if (count > 0) 581 | { 582 | if ((count == 1) && state) 583 | { 584 | changed = 1; 585 | state = 0; 586 | } 587 | 588 | count--; 589 | } 590 | else 591 | { 592 | return; 593 | } 594 | } 595 | 596 | InputState[index] = state | count; 597 | 598 | if (changed) 599 | { 600 | #if defined(SHIFT_SWITCH_INDEX) 601 | if (index == SHIFT_SWITCH_INDEX) 602 | { 603 | shift_key_cleanup = 1; 604 | } 605 | else 606 | #endif 607 | { 608 | SetNeedUpdate(index); 609 | } 610 | } 611 | } 612 | 613 | void panel_ScanInput(void) 614 | { 615 | if (shift_key_cleanup) { 616 | return; 617 | } 618 | 619 | #define MAP(port, pin, normal_id, shift_id) SetInputCount(port##pin##_index, 0 == (PIN##port & (1 << pin))); 620 | PANEL_MAPPING_TABLE(MAP) 621 | #undef MAP 622 | 623 | #if (USE_MOUSE != 0) 624 | CheckMouseUpdate(); 625 | #endif 626 | } 627 | 628 | #if (USE_CONSUMER != 0) 629 | static uint8_t ReportConsumer(void) 630 | { 631 | uint8_t i; 632 | uint8_t consumer = 0; 633 | 634 | for (i = 0; i < NUMBER_OF_INPUTS; i++) 635 | { 636 | if (IsKeyDown(i)) 637 | { 638 | uint8_t key = GetKey(i); 639 | 640 | if (IsConsumerCode(key)) { 641 | consumer |= ConsumerBit(key); 642 | } 643 | } 644 | } 645 | 646 | ReportBuffer[0] = ID_Consumer; 647 | ReportBuffer[1] = consumer; 648 | 649 | return 2; 650 | } 651 | #endif 652 | 653 | static uint8_t ReportKeyboard(void) 654 | { 655 | uint8_t i; 656 | uint8_t r = 2; 657 | 658 | memset(&ReportBuffer[1], 0x00, sizeof(ReportBuffer) - 1); 659 | 660 | ReportBuffer[0] = ID_Keyboard; 661 | 662 | for (i = 0; i < NUMBER_OF_INPUTS; i++) 663 | { 664 | if (IsKeyDown(i)) 665 | { 666 | uint8_t key = GetKey(i); 667 | 668 | if (IsKeyboardCode(key)) 669 | { 670 | if (IsModifierCode(key)) 671 | { 672 | ReportBuffer[1] |= ModifierBit(key); 673 | } 674 | else 675 | { 676 | if (r < sizeof(ReportBuffer)) 677 | { 678 | switch (key) 679 | { 680 | case KM_ALT_F4: 681 | ReportBuffer[1] |= ModifierBit(MOD_LeftAlt); 682 | ReportBuffer[r] = KEY_F4; 683 | break; 684 | case KM_SHIFT_F7: 685 | ReportBuffer[1] |= ModifierBit(MOD_LeftShift); 686 | ReportBuffer[r] = KEY_F7; 687 | break; 688 | default: 689 | ReportBuffer[r] = key; 690 | break; 691 | } 692 | 693 | r++; 694 | } 695 | } 696 | } 697 | } 698 | } 699 | 700 | return sizeof(ReportBuffer); 701 | } 702 | 703 | #if defined(ENABLE_ANALOG_INPUT) 704 | 705 | uint16_t ADC_getvalue(uint8_t id) 706 | { 707 | uint16_t x; 708 | 709 | ATOMIC_BLOCK(ATOMIC_FORCEON) 710 | { 711 | x = adc_values[id]; 712 | } 713 | 714 | return x; 715 | } 716 | 717 | static int16_t joyval12(uint16_t x, int16_t minval, int16_t maxval) 718 | { 719 | return (int16_t)(((int32_t)x * (int32_t)(maxval - minval) + (1 << 9)) >> 10) + minval - 2047; 720 | } 721 | 722 | static int8_t joyval8(uint16_t x, int16_t minval, int16_t maxval) 723 | { 724 | return (int8_t)(((int32_t)x * (int32_t)(maxval - minval) + (1 << 9)) >> 10) + minval - 127; 725 | } 726 | 727 | #endif 728 | 729 | #if (NUM_JOYSTICKS >= 1) 730 | 731 | static uint8_t ReportJoystick(uint8_t id) 732 | { 733 | uint8_t i; 734 | int16_t joy_x = 0; 735 | int16_t joy_y = 0; 736 | uint8_t joy_b = 0; 737 | 738 | ReportBuffer[0] = id; 739 | 740 | #if defined(ENABLE_ANALOG_INPUT) && defined(ADC_MAPPING_TABLE) 741 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) \ 742 | if ((axis == 0) && (joyid == id)) { joy_x = joyval12(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 4094), (int16_t)(maxval * 4094)); } \ 743 | if ((axis == 1) && (joyid == id)) { joy_y = joyval12(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 4094), (int16_t)(maxval * 4094)); } 744 | ADC_MAPPING_TABLE(MAP) 745 | #undef MAP 746 | #endif 747 | 748 | id = (id - ID_Joystick1) * NR_OF_EVENTS_PER_JOY; 749 | 750 | for (i = 0; i < NUMBER_OF_INPUTS; i++) 751 | { 752 | if (IsKeyDown(i)) 753 | { 754 | uint8_t key = GetKey(i) - id; 755 | switch (key) 756 | { 757 | case J1_Left: 758 | joy_x = -2047; 759 | break; 760 | case J1_Right: 761 | joy_x = +2047; 762 | break; 763 | case J1_Up: 764 | joy_y = -2047; 765 | break; 766 | case J1_Down: 767 | joy_y = +2047; 768 | break; 769 | 770 | case J1_Button1: 771 | case J1_Button2: 772 | case J1_Button3: 773 | case J1_Button4: 774 | case J1_Button5: 775 | case J1_Button6: 776 | case J1_Button7: 777 | case J1_Button8: 778 | joy_b |= JoyButtonBit(key); 779 | break; 780 | 781 | default: 782 | break; 783 | } 784 | } 785 | } 786 | 787 | ReportBuffer[1] = ((uint16_t)joy_x & 0xFF); 788 | ReportBuffer[2] = (((uint16_t)joy_y & 0x0F) << 4) | (((uint16_t)joy_x >> 8) & 0x0F); 789 | ReportBuffer[3] = (((uint16_t)joy_y >> 4) & 0xFF); 790 | ReportBuffer[4] = joy_b; 791 | 792 | return 5; 793 | } 794 | 795 | #endif 796 | 797 | #if (USE_ACCELGYRO) 798 | 799 | static uint8_t ReportAccelGyro() 800 | { 801 | uint8_t id = ID_AccelGyro; 802 | 803 | int8_t joy_x = 0; 804 | int8_t joy_y = 0; 805 | int8_t joy_z = 0; 806 | int8_t joy_rx = 0; 807 | int8_t joy_ry = 0; 808 | int8_t joy_rz = 0; 809 | uint8_t joy_b = 0; 810 | 811 | ReportBuffer[0] = id; 812 | 813 | #if defined(ENABLE_ANALOG_INPUT) && defined(ADC_MAPPING_TABLE) 814 | #define MAP(port, pin, mux, minval, maxval, joyid, axis) \ 815 | if ((axis == 0) && (joyid == id)) { joy_x = joyval8(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 254), (int16_t)(maxval * 254)); } \ 816 | if ((axis == 1) && (joyid == id)) { joy_y = joyval8(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 254), (int16_t)(maxval * 254)); } \ 817 | if ((axis == 2) && (joyid == id)) { joy_z = joyval8(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 254), (int16_t)(maxval * 254)); } \ 818 | if ((axis == 3) && (joyid == id)) { joy_rx = joyval8(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 254), (int16_t)(maxval * 254)); } \ 819 | if ((axis == 4) && (joyid == id)) { joy_ry = joyval8(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 254), (int16_t)(maxval * 254)); } \ 820 | if ((axis == 5) && (joyid == id)) { joy_rz = joyval8(ADC_getvalue(port##pin##_adcindex), (int16_t)(minval * 254), (int16_t)(maxval * 254)); } 821 | ADC_MAPPING_TABLE(MAP) 822 | #undef MAP 823 | #endif 824 | 825 | id = (id - ID_Joystick1) * NR_OF_EVENTS_PER_JOY; 826 | 827 | for (uint8_t i = 0; i < NUMBER_OF_INPUTS; i++) 828 | { 829 | if (IsKeyDown(i)) 830 | { 831 | uint8_t key = GetKey(i) - id; 832 | switch (key) 833 | { 834 | case J1_Left: 835 | joy_x = -127; 836 | break; 837 | case J1_Right: 838 | joy_x = +127; 839 | break; 840 | case J1_Up: 841 | joy_y = -127; 842 | break; 843 | case J1_Down: 844 | joy_y = +127; 845 | break; 846 | 847 | case J1_Button1: 848 | case J1_Button2: 849 | case J1_Button3: 850 | case J1_Button4: 851 | case J1_Button5: 852 | case J1_Button6: 853 | case J1_Button7: 854 | case J1_Button8: 855 | joy_b |= JoyButtonBit(key); 856 | break; 857 | 858 | default: 859 | break; 860 | } 861 | } 862 | } 863 | 864 | ReportBuffer[1] = joy_x; 865 | ReportBuffer[2] = joy_y; 866 | ReportBuffer[3] = joy_z; 867 | ReportBuffer[4] = joy_rx; 868 | ReportBuffer[5] = joy_ry; 869 | ReportBuffer[6] = joy_rz; 870 | ReportBuffer[7] = joy_b; 871 | 872 | return 8; 873 | } 874 | 875 | #endif 876 | 877 | 878 | #if (USE_MOUSE != 0) 879 | 880 | static uint8_t ReportMouse(void) 881 | { 882 | uint8_t i; 883 | uint8_t buttons = 0; 884 | 885 | for (i = 0; i < NUMBER_OF_INPUTS; i++) 886 | { 887 | if (IsKeyDown(i)) 888 | { 889 | uint8_t key = GetKey(i); 890 | 891 | if (IsMouseButtonCode(key)) { 892 | buttons |= MouseButtonBit(key); 893 | } 894 | } 895 | } 896 | 897 | ReportBuffer[0] = ID_Mouse; 898 | ReportBuffer[1] = buttons; 899 | ReportBuffer[2] = mouse_x_count; 900 | ReportBuffer[3] = mouse_y_count; 901 | mouse_x_count = 0; 902 | mouse_y_count = 0; 903 | 904 | return 4; 905 | } 906 | 907 | #endif 908 | 909 | 910 | static uint8_t BuildReport(uint8_t id) 911 | { 912 | switch (id) 913 | { 914 | #if (USE_KEYBOARD != 0) 915 | case ID_Keyboard: 916 | return ReportKeyboard(); 917 | #endif 918 | 919 | #if (USE_CONSUMER != 0) 920 | case ID_Consumer: 921 | return ReportConsumer(); 922 | #endif 923 | 924 | #if (NUM_JOYSTICKS >= 1) 925 | case ID_Joystick4: 926 | case ID_Joystick3: 927 | case ID_Joystick2: 928 | case ID_Joystick1: 929 | return ReportJoystick(id); 930 | #endif 931 | 932 | #if (USE_ACCELGYRO) 933 | case ID_AccelGyro: 934 | return ReportAccelGyro(id); 935 | #endif 936 | 937 | #if (USE_MOUSE != 0) 938 | case ID_Mouse: 939 | return ReportMouse(); 940 | #endif 941 | 942 | default: 943 | break; 944 | } 945 | 946 | return 0; 947 | } 948 | 949 | uint8_t panel_get_report(uint8_t **ppdata) 950 | { 951 | if (ppdata == NULL) { 952 | return 0; 953 | } 954 | 955 | static uint16_t time_next_ms = 0; 956 | uint16_t const time_curr_ms = clock_ms(); 957 | 958 | if (((int16_t)time_curr_ms - (int16_t)time_next_ms) < 0) { 959 | return 0; 960 | } 961 | 962 | time_next_ms = time_curr_ms + DELTA_TIME_PANEL_REPORT_MS; 963 | 964 | panel_ScanInput(); 965 | 966 | uint8_t const id = NeedUpdate(); 967 | 968 | if (id == ID_Unknown) { 969 | return 0; 970 | } 971 | 972 | uint8_t const ndata = BuildReport(id); 973 | *ppdata = ReportBuffer; 974 | 975 | return ndata; 976 | } 977 | 978 | 979 | #if defined(ENABLE_ANALOG_INPUT) 980 | 981 | // ADC Interrupt Routine 982 | 983 | ISR(ADC_vect) 984 | { 985 | #if defined(ENABLE_PROFILING) 986 | profile_start(); 987 | #endif 988 | 989 | static int i = 0; 990 | 991 | // get value 992 | 993 | adc_values[i] = ADC; 994 | 995 | // cycle 996 | 997 | i -= 1; 998 | 999 | if (i < 0) 1000 | i += NUM_ADC_CHANNELS; 1001 | 1002 | // set mux channel for the next conversion 1003 | 1004 | ADC_setmux(adc_mux_table[i]); 1005 | 1006 | // start new conversion 1007 | 1008 | ADCSRA |= (1 << ADSC); 1009 | } 1010 | 1011 | #endif 1012 | 1013 | 1014 | 1015 | #endif 1016 | -------------------------------------------------------------------------------- /firmware/panel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | /* Name: hid_input.h 18 | * Project: V-USB Mame Panel 19 | * Author: Andreas Oberdorfer 20 | * Creation Date: 2009-09-19 21 | * Copyright 2009 - 2011 Andreas Oberdorfer 22 | * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) 23 | */ 24 | 25 | #ifndef PANEL_H__INCLUDED 26 | #define PANEL_H__INCLUDED 27 | 28 | #include 29 | 30 | 31 | enum ReportIds 32 | { 33 | ID_Unknown = 0, 34 | ID_Keyboard, 35 | ID_Consumer, 36 | ID_Joystick1, 37 | ID_Joystick2, 38 | ID_Joystick3, 39 | ID_Joystick4, 40 | ID_AccelGyro, 41 | ID_Mouse, 42 | }; 43 | 44 | static const uint16_t DELTA_TIME_PANEL_REPORT_MS = 2; 45 | 46 | void panel_init(void); 47 | uint8_t panel_get_report(uint8_t **ppdata); 48 | 49 | 50 | 51 | #endif // PANEL_H__INCLUDED 52 | -------------------------------------------------------------------------------- /firmware/queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include "queue.h" 19 | 20 | 21 | static uint8_t fifo_getlevel(fifo_t const *f) { return f->wpos - f->rpos; } 22 | static uint8_t fifo_getfree(fifo_t const *f) { return f->mask - fifo_getlevel(f) + 1; } 23 | 24 | 25 | int8_t queue_push(fifo_t *f, uint8_t x) 26 | { 27 | uint8_t const nfree = fifo_getfree(f); 28 | 29 | if (nfree == 0) 30 | return -1; 31 | 32 | uint8_t const index = f->wpos & f->mask; 33 | f->buf[index] = x; 34 | f->wpos += 1; 35 | 36 | return 0; 37 | } 38 | 39 | 40 | int8_t queue_pop(fifo_t *f, uint8_t *px) 41 | { 42 | uint8_t const ndata = fifo_getlevel(f); 43 | 44 | if (ndata == 0 || px == NULL) 45 | return -1; 46 | 47 | uint8_t const index = f->rpos & f->mask; 48 | *px = f->buf[index]; 49 | f->rpos += 1; 50 | 51 | return 0; 52 | } 53 | 54 | 55 | uint8_t* chunk_peek(fifo_t *f) 56 | { 57 | uint8_t const ndata = fifo_getlevel(f); 58 | 59 | if (ndata == 0) 60 | return NULL; 61 | 62 | uint8_t index = f->rpos & f->mask; 63 | 64 | return &f->buf[index]; 65 | } 66 | 67 | 68 | void chunk_release(fifo_t *f) 69 | { 70 | f->rpos += f->chunksize; 71 | } 72 | 73 | 74 | uint8_t* chunk_prepare(fifo_t *f) 75 | { 76 | uint8_t const nfree = fifo_getfree(f); 77 | 78 | if (nfree == 0) 79 | return NULL; 80 | 81 | uint8_t index = f->wpos & f->mask; 82 | 83 | return &f->buf[index]; 84 | } 85 | 86 | 87 | void chunk_push(fifo_t* f) 88 | { 89 | f->wpos += f->chunksize; 90 | } 91 | -------------------------------------------------------------------------------- /firmware/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef QUEUE_H_INCLUDED 18 | #define QUEUE_H_INCLUDED 19 | 20 | #include 21 | #include 22 | 23 | 24 | typedef struct { 25 | uint8_t volatile rpos; 26 | uint8_t volatile wpos; 27 | uint8_t chunksize; 28 | uint8_t mask; 29 | uint8_t volatile buf[1]; 30 | } fifo_t; 31 | 32 | 33 | // helper to allocate and initialize a fifo buffer 34 | #define CREATE_FIFO(_name_, _num_chunks_log2_, _chunksize_log2_) \ 35 | union { \ 36 | uint8_t volatile _name_##_buffer__[sizeof(fifo_t) - 1 + (1 << (_num_chunks_log2_ + _chunksize_log2_))]; \ 37 | fifo_t fifo; \ 38 | } _name_##_fifo__ = { \ 39 | .fifo.chunksize = (1 << (_chunksize_log2_)), \ 40 | .fifo.mask = ((1 << (_num_chunks_log2_ + _chunksize_log2_)) - 1) \ 41 | }; \ 42 | fifo_t * const _name_ = &_name_##_fifo__.fifo; 43 | 44 | 45 | int8_t queue_push(fifo_t *f, uint8_t x); 46 | int8_t queue_pop(fifo_t *f, uint8_t *px); 47 | 48 | uint8_t* chunk_prepare(fifo_t *f); 49 | void chunk_push(fifo_t *f); 50 | uint8_t* chunk_peek(fifo_t *f); 51 | void chunk_release(fifo_t *f); 52 | 53 | 54 | 55 | #endif 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | LWCloneU2 2 | ========= 3 | 4 | A firmware for Atmel AVR microcontroller for controlling LEDs or Light Bulbs via USB *and* a Joystick/Mouse/Keyboard Encoder. 5 | 6 | The device is compatible with the LED-WIZ controller on the USB protocol level and thus can be used with many existing software. 7 | Additionally the firmware allows to add panel support, i.e. up to 4 yoysticks, 1 mouse, 1 keyboard and more. That is with one board you can get an input encoder and an LED output controller perfectly suited for MAME. 8 | 9 | The LWCloneU2 project contains a compatible driver DLL "ledwiz.dll" replacement that fixes some bugs of the original one and does not block your main application, i.e. the I/O is fully asynchron. 10 | 11 | 12 | Supported Hardware 13 | ================== 14 | - Custom Breakout Board with ATMega32U2 15 | - Arduino Leonardo (ATMega32U4) 16 | - Arduino Mega 2560 (tested with Rev. 3) 17 | - Arduino Uno Rev. 2/3 (untested) 18 | 19 | 20 | Building the firmware 21 | ===================== 22 | 23 | In order to build all this, you need a recent toolchain for AVR microcontroller, e.g. the 'AVR Toolchain 3.4.2-1573' from Atmel or the one that is bundled with the Atmel AVRStudio. 24 | Get the sources from the Git repository, then do a 'git submodule update --init' in order to get the required LUFA (USB framework) sources. Then a 'make' should build the firmwares for all supported platforms. 25 | 26 | 27 | Building the Windows DLL 28 | ======================== 29 | 30 | There are project files for Visualstudio 2008 Express and Visualstudio 2012 Express. The VS 2012 solution supports creating a 64 bit DLL. 31 | -------------------------------------------------------------------------------- /schematic/breakout32u2.brd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cithraidt/lwcloneu2/40e39ac1b384716857c1152be3767d8e6d0bd674/schematic/breakout32u2.brd -------------------------------------------------------------------------------- /schematic/breakout32u2.sch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cithraidt/lwcloneu2/40e39ac1b384716857c1152be3767d8e6d0bd674/schematic/breakout32u2.sch -------------------------------------------------------------------------------- /win32/driver/build/vs_2008/ledwiz.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ledwiz", "ledwiz.vcproj", "{E498CD63-429C-4443-BA3E-CC0600379F31}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {E498CD63-429C-4443-BA3E-CC0600379F31}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {E498CD63-429C-4443-BA3E-CC0600379F31}.Debug|Win32.Build.0 = Debug|Win32 14 | {E498CD63-429C-4443-BA3E-CC0600379F31}.Release|Win32.ActiveCfg = Release|Win32 15 | {E498CD63-429C-4443-BA3E-CC0600379F31}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /win32/driver/build/vs_2008/ledwiz.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 101 | 104 | 107 | 110 | 113 | 116 | 133 | 136 | 139 | 142 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 174 | 175 | 176 | 177 | 178 | 179 | 182 | 183 | 186 | 187 | 190 | 191 | 194 | 195 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /win32/driver/build/vs_2012/ledwiz.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ledwiz", "ledwiz.vcxproj", "{255DA939-7CAD-4705-A71E-DCCE0FD0FA84}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Debug|Win32.ActiveCfg = Release|Win32 15 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Debug|Win32.Build.0 = Release|Win32 16 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Debug|x64.ActiveCfg = Release|x64 17 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Debug|x64.Build.0 = Release|x64 18 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Release|Win32.ActiveCfg = Release|Win32 19 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Release|Win32.Build.0 = Release|Win32 20 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Release|x64.ActiveCfg = Release|x64 21 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /win32/driver/build/vs_2012/ledwiz.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {255DA939-7CAD-4705-A71E-DCCE0FD0FA84} 23 | Win32Proj 24 | ledwiz 25 | 26 | 27 | 28 | DynamicLibrary 29 | true 30 | v110 31 | MultiByte 32 | 33 | 34 | DynamicLibrary 35 | true 36 | v110 37 | MultiByte 38 | 39 | 40 | DynamicLibrary 41 | false 42 | false 43 | MultiByte 44 | v110 45 | 46 | 47 | DynamicLibrary 48 | false 49 | false 50 | MultiByte 51 | v110 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | ..\..\bin\ 72 | 73 | 74 | true 75 | ..\..\bin\x64\ 76 | 77 | 78 | false 79 | ..\..\bin\ 80 | 81 | 82 | false 83 | ..\..\bin\x64\ 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_WINDOWS;_USRDLL;LEDWIZ_EXPORTS;%(PreprocessorDefinitions) 92 | ..\..\include 93 | 94 | 95 | Windows 96 | true 97 | hid.lib;Setupapi.lib;%(AdditionalDependencies) 98 | ../../src/ledwiz.def 99 | 100 | 101 | 102 | 103 | 104 | 105 | Level3 106 | Disabled 107 | WIN32;_DEBUG;_WINDOWS;_USRDLL;LEDWIZ_EXPORTS;%(PreprocessorDefinitions) 108 | ..\..\include 109 | 110 | 111 | Windows 112 | true 113 | hid.lib;Setupapi.lib;%(AdditionalDependencies) 114 | ../../src/ledwiz.def 115 | 116 | 117 | 118 | 119 | Level3 120 | 121 | 122 | MaxSpeed 123 | false 124 | true 125 | WIN32;NDEBUG;_WINDOWS;_USRDLL;LEDWIZ_EXPORTS;%(PreprocessorDefinitions) 126 | ..\..\include 127 | OnlyExplicitInline 128 | Speed 129 | true 130 | false 131 | false 132 | 133 | 134 | Windows 135 | false 136 | true 137 | true 138 | hid.lib;Setupapi.lib;%(AdditionalDependencies) 139 | ../../src/ledwiz.def 140 | 141 | 142 | 143 | 144 | Level3 145 | 146 | 147 | MaxSpeed 148 | false 149 | true 150 | WIN32;NDEBUG;_WINDOWS;_USRDLL;LEDWIZ_EXPORTS;%(PreprocessorDefinitions) 151 | ..\..\include 152 | OnlyExplicitInline 153 | Speed 154 | true 155 | false 156 | false 157 | 158 | 159 | Windows 160 | false 161 | true 162 | true 163 | hid.lib;Setupapi.lib;%(AdditionalDependencies) 164 | ../../src/ledwiz.def 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /win32/driver/build/vs_2012/ledwiz.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /win32/driver/include/ledwiz.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef LEDWIZ_H__INCLUDED 3 | #define LEDWIZ_H__INCLUDED 4 | 5 | 6 | #if defined(_MSC_VER) 7 | 8 | #define LWZCALL __cdecl // this is what the 'original' ledwiz.dll uses 9 | #define LWZCALLBACK __stdcall 10 | 11 | #if (_MSC_VER >= 1600) // starting with VisualStudio 2010 stdint.h is available 12 | #include 13 | #else 14 | typedef signed char int8_t; 15 | typedef unsigned char uint8_t; 16 | typedef short int16_t; 17 | typedef unsigned short uint16_t; 18 | typedef int int32_t; 19 | typedef unsigned int uint32_t; 20 | #endif 21 | 22 | #else 23 | 24 | #include 25 | #define LWZCALL 26 | #define LWZCALLBACK 27 | 28 | #endif 29 | 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | 36 | #define LWZ_MAX_DEVICES 16 37 | 38 | typedef enum { 39 | LWZ_REASON_ADD = 1, 40 | LWZ_REASON_DELETE = 2, 41 | } LWZ_NOTIFY_REASON; 42 | 43 | 44 | typedef int32_t LWZHANDLE; 45 | 46 | 47 | typedef struct { 48 | LWZHANDLE handles[LWZ_MAX_DEVICES]; 49 | int32_t numdevices; 50 | } LWZDEVICELIST; 51 | 52 | 53 | /************************************************************************************************************************ 54 | LWZ_SBA - All Outputs State plus Global Pulse Speed 55 | ************************************************************************************************************************* 56 | handle is an idetifier for a specific LED-WIZ device 57 | Values bank0, bank1, bank2, and bank3 equal 8-bit representations of on/off states for banks 1-4. 58 | Value globalPulseSpeed equals Global Pulse Speed setting (1 through 7). 59 | ************************************************************************************************************************/ 60 | 61 | void LWZCALL LWZ_SBA( 62 | LWZHANDLE hlwz, 63 | uint8_t bank0, 64 | uint8_t bank1, 65 | uint8_t bank2, 66 | uint8_t bank3, 67 | uint8_t globalPulseSpeed); 68 | 69 | 70 | /************************************************************************************************************************ 71 | LWZ_PBA - All Outputs Profile Settings (Most Efficient): 72 | ************************************************************************************************************************* 73 | handle is an idetifier for a specific LED-WIZ device 74 | Each of the 32 parameters coincide with outputs 1-32. A value of 1 to 48 sets the brightness of each LED using PWM. 75 | A value of 129-132 indicates an automated pulse mode as follows: 76 | 129 = Ramp Up / Ramp Down 77 | 130 = On / Off 78 | 131 = On / Ramp Down 79 | 132 = Ramp Up / On 80 | The speed is contolled by the Global Pulse Speed parameter. 81 | ************************************************************************************************************************/ 82 | 83 | void LWZCALL LWZ_PBA(LWZHANDLE hlwz, uint8_t const *pmode32bytes); 84 | 85 | 86 | /************************************************************************************************************************ 87 | LWZ_REGISTER - Register device for plug and play 88 | ************************************************************************************************************************* 89 | This must be called with the hwnd that an application uses to process windows messages. 90 | This associates a device with a window message queue so the your application can be notified of plug/unplug events. 91 | In order to unregister, call with hwnd == NULL. 92 | You have to unregister if the library was manually loaded and then is going to be freed with FreeLibrary() while 93 | the window still exists. 94 | ************************************************************************************************************************/ 95 | 96 | void LWZCALL LWZ_REGISTER(LWZHANDLE hlwz, void * hwnd); 97 | 98 | 99 | /************************************************************************************************************************ 100 | LWZ_SET_NOTIFY - Set notifcation mechanisms for plug/unplug events 101 | LWZ_SET_NOTIFY_EX - same as LWZ_SET_NOTIFY, but provides a user defined pointer in the callback 102 | ************************************************************************************************************************* 103 | Set a notification callback for plug/unplug events. 104 | It searches for all connected LED-WIZ devices and then calls the notify callback for it. 105 | The callback will come back directly from this call or later from the windows procedure thread of the caller, 106 | that is as long as you do your stuff from the same windows procedure there will be no need for thread synchronization. 107 | At the same time the notification procedure is called, the LWZDEVICELIST 108 | will be updated with any new device handles that are required. 109 | This function is also used to set a pointer to your applications device list. 110 | ************************************************************************************************************************/ 111 | 112 | typedef void (LWZCALLBACK * LWZNOTIFYPROC)(int32_t reason, LWZHANDLE hlwz); 113 | typedef void (LWZCALLBACK * LWZNOTIFYPROC_EX)(void *puser, int32_t reason, LWZHANDLE hlwz); 114 | 115 | void LWZCALL LWZ_SET_NOTIFY(LWZNOTIFYPROC notify_callback, LWZDEVICELIST *plist); 116 | void LWZCALL LWZ_SET_NOTIFY_EX(LWZNOTIFYPROC_EX notify_ex_callback, void *puser, LWZDEVICELIST *plist); 117 | 118 | 119 | /************************************************************************************************************************ 120 | LWZ_RAWWRITE - write raw data to the device 121 | ************************************************************************************************************************* 122 | return number of bytes written. 123 | ************************************************************************************************************************/ 124 | 125 | uint32_t LWZ_RAWWRITE(LWZHANDLE hlwz, uint8_t const *pdata, uint32_t ndata); 126 | 127 | /************************************************************************************************************************ 128 | LWZ_RAWREAD - read raw data from the device 129 | ************************************************************************************************************************* 130 | return number of bytes read. 131 | ************************************************************************************************************************/ 132 | 133 | uint32_t LWZ_RAWREAD(LWZHANDLE hlwz, uint8_t *pdata, uint32_t ndata); 134 | 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /win32/driver/src/ledwiz.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | LWZ_SBA 3 | LWZ_PBA 4 | LWZ_RAWWRITE 5 | LWZ_RAWREAD 6 | LWZ_REGISTER 7 | LWZ_SET_NOTIFY 8 | LWZ_SET_NOTIFY_EX 9 | -------------------------------------------------------------------------------- /win32/driver/src/usbdev.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include "usbdev.h" 20 | 21 | 22 | static void usbdev_close_internal(HUDEV hudev); 23 | 24 | #define USB_READ_TIMOUT_MS 500 25 | 26 | 27 | 28 | struct CAutoLockCS // helper class to lock a critical section, and unlock it automatically 29 | { 30 | CRITICAL_SECTION *m_pcs; 31 | CAutoLockCS(CRITICAL_SECTION *pcs) { m_pcs = pcs; EnterCriticalSection(m_pcs); }; 32 | ~CAutoLockCS() { LeaveCriticalSection(m_pcs); }; 33 | }; 34 | 35 | #define AUTOLOCK(cs) CAutoLockCS lock_##__LINE__##__(&cs) // helper macro for using the helper class 36 | 37 | 38 | 39 | typedef struct { 40 | CRITICAL_SECTION cslock; 41 | HANDLE hrevent; 42 | HANDLE hwevent; 43 | HANDLE hdev; 44 | LONG refcount; 45 | } usbdev_context_t; 46 | 47 | 48 | HUDEV usbdev_create(LPCSTR devicepath) 49 | { 50 | // create context 51 | 52 | usbdev_context_t * const h = (usbdev_context_t*)malloc(sizeof(usbdev_context_t)); 53 | 54 | if (h == NULL) 55 | return NULL; 56 | 57 | memset(h, 0x00, sizeof(*h)); 58 | h->hdev = INVALID_HANDLE_VALUE; 59 | 60 | InitializeCriticalSection(&h->cslock); 61 | 62 | h->hrevent = CreateEvent(NULL, TRUE, FALSE, NULL); 63 | h->hwevent = CreateEvent(NULL, TRUE, FALSE, NULL); 64 | 65 | if (h->hrevent == NULL || 66 | h->hwevent == NULL) 67 | { 68 | goto Failed; 69 | } 70 | 71 | // open device 72 | 73 | HANDLE hdev = CreateFileA( 74 | devicepath, 75 | GENERIC_READ | GENERIC_WRITE, 76 | FILE_SHARE_READ | FILE_SHARE_WRITE, 77 | NULL, 78 | OPEN_EXISTING, 79 | FILE_FLAG_OVERLAPPED, 80 | NULL); 81 | 82 | if (hdev != INVALID_HANDLE_VALUE) 83 | { 84 | h->hdev = hdev; 85 | h->refcount = 1; 86 | return h; 87 | } 88 | 89 | Failed: 90 | usbdev_close_internal(h); 91 | return NULL; 92 | } 93 | 94 | static void usbdev_close_internal(HUDEV hudev) 95 | { 96 | usbdev_context_t * const h = (usbdev_context_t*)hudev; 97 | 98 | if (h == NULL) 99 | return; 100 | 101 | if (h->hrevent) 102 | { 103 | CloseHandle(h->hrevent); 104 | h->hrevent = NULL; 105 | } 106 | 107 | if (h->hwevent) 108 | { 109 | CloseHandle(h->hwevent); 110 | h->hwevent = NULL; 111 | } 112 | 113 | if (h->hdev != INVALID_HANDLE_VALUE) 114 | { 115 | CloseHandle(h->hdev); 116 | h->hdev = INVALID_HANDLE_VALUE; 117 | } 118 | 119 | DeleteCriticalSection(&h->cslock); 120 | 121 | free(h); 122 | } 123 | 124 | void usbdev_release(HUDEV hudev) 125 | { 126 | usbdev_context_t * const h = (usbdev_context_t*)hudev; 127 | 128 | if (h != NULL) 129 | { 130 | LONG refcount_new = InterlockedDecrement(&h->refcount); 131 | 132 | if (refcount_new <= 0) 133 | { 134 | usbdev_close_internal(h); 135 | } 136 | } 137 | } 138 | 139 | void usbdev_addref(HUDEV hudev) 140 | { 141 | usbdev_context_t * const h = (usbdev_context_t*)hudev; 142 | 143 | if (h != NULL) 144 | { 145 | InterlockedIncrement(&h->refcount); 146 | } 147 | } 148 | 149 | HANDLE usbdev_handle(HUDEV hudev) 150 | { 151 | usbdev_context_t * const h = (usbdev_context_t*)hudev; 152 | 153 | if (h == NULL) 154 | return INVALID_HANDLE_VALUE; 155 | 156 | return h->hdev; 157 | } 158 | 159 | size_t usbdev_read(HUDEV hudev, void *psrc, size_t ndata) 160 | { 161 | usbdev_context_t * const h = (usbdev_context_t*)hudev; 162 | 163 | if (h == NULL) 164 | return NULL; 165 | 166 | BYTE * pdata = (BYTE*)psrc; 167 | 168 | if (pdata == NULL) 169 | return 0; 170 | 171 | if (ndata > 64) 172 | ndata = 64; 173 | 174 | AUTOLOCK(h->cslock); 175 | 176 | int res = 0; 177 | BYTE buffer[65]; 178 | DWORD nread = 0; 179 | BOOL bres = FALSE; 180 | 181 | OVERLAPPED ol = {}; 182 | ol.hEvent = h->hrevent; 183 | 184 | bres = ReadFile(h->hdev, buffer, sizeof(buffer), NULL, &ol); 185 | 186 | if (bres != TRUE) 187 | { 188 | DWORD dwerror = GetLastError(); 189 | 190 | if (dwerror == ERROR_IO_PENDING) 191 | { 192 | if (WaitForSingleObject(h->hrevent, USB_READ_TIMOUT_MS) != WAIT_OBJECT_0) 193 | { 194 | CancelIo(h->hdev); 195 | } 196 | 197 | bres = TRUE; 198 | } 199 | } 200 | 201 | if (bres == TRUE) 202 | { 203 | bres = GetOverlappedResult( 204 | h->hdev, 205 | &ol, 206 | &nread, 207 | TRUE); 208 | } 209 | 210 | if (bres != TRUE) 211 | { 212 | DWORD dwerror = GetLastError(); 213 | _ASSERT(0); 214 | } 215 | 216 | if (nread <= 1 || bres != TRUE) 217 | return 0; 218 | 219 | nread -= 1; // skip report id 220 | 221 | if (ndata > nread) 222 | ndata = nread; 223 | 224 | memcpy(pdata, &buffer[1], ndata); 225 | 226 | return ndata; 227 | } 228 | 229 | size_t usbdev_write(HUDEV hudev, void const *pdst, size_t ndata) 230 | { 231 | usbdev_context_t * const h = (usbdev_context_t*)hudev; 232 | 233 | if (h == NULL) 234 | return NULL; 235 | 236 | BYTE const * pdata = (BYTE const *)pdst; 237 | 238 | if (pdata == NULL || ndata == 0) 239 | return 0; 240 | 241 | if (ndata > 32) 242 | ndata = 32; 243 | 244 | AUTOLOCK(h->cslock); 245 | 246 | int res = 0; 247 | DWORD nbyteswritten = 0; 248 | 249 | BYTE buf[9]; 250 | buf[0] = 0; // report id 251 | 252 | while (ndata > 0) 253 | { 254 | int const ncopy = (ndata > 8) ? 8 : ndata; 255 | 256 | memset(&buf[1], 0x00, 8); 257 | memcpy(&buf[1], pdata, ncopy); 258 | pdata += ncopy; 259 | ndata -= ncopy; 260 | 261 | DWORD nwritten = 0; 262 | DWORD const nwrite = 9; 263 | 264 | OVERLAPPED ol = {}; 265 | ol.hEvent = h->hwevent; 266 | 267 | BOOL bres = WriteFile(h->hdev, buf, nwrite, NULL, &ol); 268 | 269 | if (bres != TRUE) 270 | { 271 | DWORD dwerror = GetLastError(); 272 | 273 | if (dwerror == ERROR_IO_PENDING) 274 | { 275 | if (WaitForSingleObject(h->hwevent, USB_READ_TIMOUT_MS) != WAIT_OBJECT_0) 276 | { 277 | CancelIo(h->hdev); 278 | } 279 | 280 | bres = TRUE; 281 | } 282 | } 283 | 284 | if (bres == TRUE) 285 | { 286 | bres = GetOverlappedResult( 287 | h->hdev, 288 | &ol, 289 | &nwritten, 290 | TRUE); 291 | } 292 | 293 | if (bres != TRUE) 294 | { 295 | DWORD dwerror = GetLastError(); 296 | _ASSERT(0); 297 | } 298 | 299 | if (nwritten != nwrite || bres != TRUE) { 300 | break; 301 | } 302 | 303 | nbyteswritten += ncopy; 304 | } 305 | 306 | return nbyteswritten; 307 | } 308 | 309 | -------------------------------------------------------------------------------- /win32/driver/src/usbdev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #ifndef USBDEV_H__INCLUDED 18 | #define USBDEV_H__INCLUDED 19 | 20 | 21 | typedef void * HUDEV; 22 | 23 | HUDEV usbdev_create(LPCSTR devicepath); 24 | void usbdev_addref(HUDEV hudev); 25 | void usbdev_release(HUDEV hudev); 26 | size_t usbdev_read(HUDEV hudev, void *pdata, size_t ndata); 27 | size_t usbdev_write(HUDEV hudev, void const *pdata, size_t ndata); 28 | HANDLE usbdev_handle(HUDEV hudev); 29 | 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /win32/lwcconfig/build/vs_2008/lwcconfig.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwcconfig", "lwcconfig.vcproj", "{591A86C4-AE9B-4839-AE3A-63D22CEEB84D}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {591A86C4-AE9B-4839-AE3A-63D22CEEB84D}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {591A86C4-AE9B-4839-AE3A-63D22CEEB84D}.Debug|Win32.Build.0 = Debug|Win32 14 | {591A86C4-AE9B-4839-AE3A-63D22CEEB84D}.Release|Win32.ActiveCfg = Release|Win32 15 | {591A86C4-AE9B-4839-AE3A-63D22CEEB84D}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /win32/lwcconfig/build/vs_2008/lwcconfig.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 91 | 99 | 102 | 105 | 108 | 111 | 114 | 126 | 129 | 132 | 135 | 144 | 147 | 150 | 153 | 156 | 159 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 175 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /win32/lwcconfig/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | 27 | #define LEDWIZ_DLL_NAME "ledwiz.dll" 28 | 29 | 30 | struct { 31 | 32 | struct { 33 | void (LWZCALL * LWZ_SBA) (LWZHANDLE hlwz, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t gps); 34 | void (LWZCALL * LWZ_PBA) (LWZHANDLE hlwz, uint8_t const *pmode32bytes); 35 | int (LWZCALL * LWZ_RAWWRITE) (LWZHANDLE hlwz, uint8_t const *pdata, uint32_t ndata); 36 | void (LWZCALL * LWZ_REGISTER) (LWZHANDLE hlwz, void * hwnd); 37 | void (LWZCALL * LWZ_SET_NOTIFY) (LWZNOTIFYPROC notify_callback, LWZDEVICELIST *plist); 38 | } fn; 39 | 40 | HMODULE hdll; 41 | HWND hwnd; 42 | HANDLE hthread; 43 | 44 | LWZDEVICELIST devlist; 45 | 46 | } g_main = {0}; 47 | 48 | 49 | static void CALLBACK notify_cb(int32_t reason, LWZHANDLE hlwz) 50 | { 51 | if (reason == LWZ_REASON_ADD) 52 | { 53 | printf("ledwiz device found, id: %d\n", hlwz); 54 | 55 | g_main.fn.LWZ_REGISTER(hlwz, g_main.hwnd); 56 | } 57 | else if (reason == LWZ_REASON_DELETE) 58 | { 59 | printf("ledwiz device removed, id: %d\n", hlwz); 60 | } 61 | } 62 | 63 | 64 | void usage() 65 | { 66 | printf("\n"); 67 | printf("Usage:\n\n"); 68 | printf("lwcconfig [-m] [-p ] []\n"); 69 | printf(" -h .................... help\n"); 70 | printf(" -p ........... program new id\n"); 71 | printf(" -m .................... measure I/O bandwidth\n"); 72 | printf("\n"); 73 | } 74 | 75 | 76 | int main(int argc, char* argv[]) 77 | { 78 | // parse arguments 79 | 80 | const char * p_arg = NULL; 81 | const char * id_arg = NULL; 82 | bool do_measure_bandwidth = false; 83 | int err = 0; 84 | 85 | for (int i = 1; i < argc && err == 0; i++) 86 | { 87 | if (argv[i][0] == '-') 88 | { 89 | switch (argv[i][1]) { 90 | case 'm': 91 | { 92 | do_measure_bandwidth = true; 93 | break; 94 | } 95 | case 'h': 96 | { 97 | err = 1; 98 | break; 99 | } 100 | case 'p': 101 | { 102 | p_arg = &argv[i][2]; 103 | 104 | if (p_arg[0] == '\0' && (i+1) < argc) { 105 | p_arg = argv[++i]; 106 | } 107 | 108 | break; 109 | } 110 | default: 111 | { 112 | err = -4; 113 | } 114 | } 115 | } 116 | else 117 | { 118 | if (id_arg != NULL) { 119 | err = -5; 120 | } else { 121 | id_arg = argv[i]; 122 | } 123 | } 124 | } 125 | 126 | printf("\n"); 127 | 128 | if (err < 0) 129 | { 130 | printf("invalid argument(s), %d", err); 131 | usage(); 132 | goto Failed; 133 | } 134 | else if (err != 0) 135 | { 136 | usage(); 137 | goto Failed; 138 | } 139 | 140 | // load the ledwiz.dll 141 | 142 | g_main.hdll = LoadLibraryA(LEDWIZ_DLL_NAME); 143 | 144 | if (g_main.hdll == NULL) 145 | { 146 | printf("loading " LEDWIZ_DLL_NAME " failed!\n"); 147 | return -1; 148 | } 149 | 150 | ((void**)&g_main.fn.LWZ_SBA)[0] = GetProcAddress(g_main.hdll, "LWZ_SBA"); 151 | ((void**)&g_main.fn.LWZ_PBA)[0] = GetProcAddress(g_main.hdll, "LWZ_PBA"); 152 | ((void**)&g_main.fn.LWZ_RAWWRITE)[0] = GetProcAddress(g_main.hdll, "LWZ_RAWWRITE"); 153 | ((void**)&g_main.fn.LWZ_REGISTER)[0] = GetProcAddress(g_main.hdll, "LWZ_REGISTER"); 154 | ((void**)&g_main.fn.LWZ_SET_NOTIFY)[0] = GetProcAddress(g_main.hdll, "LWZ_SET_NOTIFY"); 155 | 156 | if (g_main.fn.LWZ_SBA == NULL || 157 | g_main.fn.LWZ_PBA == NULL || 158 | g_main.fn.LWZ_REGISTER == NULL || 159 | g_main.fn.LWZ_SET_NOTIFY == NULL) 160 | { 161 | printf("getting the function addresses failed!\n"); 162 | goto Failed; 163 | } 164 | 165 | // enumerate LED wiz devices 166 | 167 | g_main.fn.LWZ_SET_NOTIFY(notify_cb, &g_main.devlist); 168 | 169 | if (g_main.devlist.numdevices <= 0) 170 | { 171 | printf("no ledwiz devices detected!\n"); 172 | goto Failed; 173 | } 174 | 175 | // verify options 176 | 177 | if (!do_measure_bandwidth && 178 | p_arg == NULL) 179 | { 180 | usage(); 181 | goto Failed; 182 | } 183 | 184 | // measure bandwidth 185 | 186 | if (do_measure_bandwidth) 187 | { 188 | printf("measuring bandwidth ...\n"); 189 | 190 | int const duration_ms_max = 500; 191 | uint8_t x32bytes[32] = {0}; 192 | int nsend = 0; 193 | int nsend_total = 0; 194 | int nduration_ms = 0; 195 | clock_t t0; 196 | 197 | // step 1: send as much data as possible within some fixed time to fill the input buffer 198 | 199 | t0 = clock(); 200 | 201 | for (;;) 202 | { 203 | g_main.fn.LWZ_PBA(g_main.devlist.handles[0], &x32bytes[0]); 204 | nsend += 32; 205 | 206 | clock_t t1 = clock(); 207 | nduration_ms = ((t1 - t0) * 1000) / CLOCKS_PER_SEC; 208 | 209 | if (nduration_ms > duration_ms_max) { 210 | break; 211 | } 212 | } 213 | 214 | nsend_total += nsend; 215 | 216 | // step 2: measure average throughput 217 | 218 | nsend = 0; 219 | nduration_ms = 0; 220 | t0 = clock(); 221 | 222 | for (;;) 223 | { 224 | g_main.fn.LWZ_PBA(g_main.devlist.handles[0], &x32bytes[0]); 225 | nsend += 32; 226 | 227 | clock_t t1 = clock(); 228 | nduration_ms = ((t1 - t0) * 1000) / CLOCKS_PER_SEC; 229 | 230 | if (nduration_ms > duration_ms_max) { 231 | break; 232 | } 233 | } 234 | 235 | nsend_total += nsend; 236 | double bps_avg = (double)nsend * 1000.0 / (double)nduration_ms; 237 | 238 | // step 3: measure burst blocksize 239 | 240 | Sleep((int)((double)nsend_total / bps_avg * 1000.0) + 100); // wait some time until the buffer is again free 241 | 242 | nsend = 0; 243 | nduration_ms = 0; 244 | t0 = clock(); 245 | 246 | for (;;) 247 | { 248 | g_main.fn.LWZ_PBA(g_main.devlist.handles[0], &x32bytes[0]); 249 | nsend += 32; 250 | 251 | clock_t t1 = clock(); 252 | nduration_ms = ((t1 - t0) * 1000) / CLOCKS_PER_SEC; 253 | 254 | if (nduration_ms > duration_ms_max) { 255 | break; 256 | } 257 | } 258 | 259 | int nsend_burst = nsend - (int)((double)nduration_ms * bps_avg / 1000.0); 260 | 261 | if (nsend_burst < 0) { 262 | nsend_burst = 0; 263 | } 264 | 265 | printf("average rate: %0.2f kByte/s, burst blocksize: %d Byte\n", bps_avg / 1024.0, nsend_burst); 266 | } 267 | 268 | // reprogram new id 269 | 270 | if (p_arg && g_main.devlist.numdevices > 0) 271 | { 272 | if (g_main.fn.LWZ_RAWWRITE == NULL) { 273 | printf("invalid or old version ledwiz.dll! please update"); 274 | goto Failed; 275 | } 276 | 277 | int const id_old = (id_arg != NULL) ? atoi(id_arg) : g_main.devlist.handles[0]; 278 | int const id_new = atoi(p_arg); 279 | 280 | if (id_new < 1 || id_new >= 32 || id_new == id_old) 281 | { 282 | printf("invalid id specified!\n"); 283 | goto Failed; 284 | } 285 | 286 | int index = -1; 287 | for (int i = 0; i < g_main.devlist.numdevices; i++) 288 | { 289 | if (g_main.devlist.handles[i] == id_old) 290 | { 291 | index = i; 292 | break; 293 | } 294 | } 295 | 296 | if (index < 0) 297 | { 298 | printf("device with id=%d not found!\n", id_old); 299 | } 300 | else 301 | { 302 | // send change ID command 303 | printf("sending change-id-command to device %d, new id: %d\n", id_old, id_new); 304 | 305 | uint8_t const LWCCONFIG_CMD_SETID = 65; 306 | uint8_t const id = id_new - 1; 307 | uint8_t const check = ~id; 308 | 309 | uint8_t buf[8] = {LWCCONFIG_CMD_SETID, id, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, check}; 310 | 311 | g_main.fn.LWZ_RAWWRITE(g_main.devlist.handles[index], buf, sizeof(buf)); 312 | } 313 | } 314 | 315 | Failed: 316 | if (g_main.hdll) 317 | { 318 | FreeLibrary(g_main.hdll); 319 | g_main.hdll = NULL; 320 | } 321 | 322 | return 0; 323 | } 324 | -------------------------------------------------------------------------------- /win32/testapp/build/vs_2008/testapp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testapp", "testapp.vcproj", "{B56B9055-7ABE-4231-8D9E-DC7ED80739DE}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {B56B9055-7ABE-4231-8D9E-DC7ED80739DE}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {B56B9055-7ABE-4231-8D9E-DC7ED80739DE}.Debug|Win32.Build.0 = Debug|Win32 14 | {B56B9055-7ABE-4231-8D9E-DC7ED80739DE}.Release|Win32.ActiveCfg = Release|Win32 15 | {B56B9055-7ABE-4231-8D9E-DC7ED80739DE}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /win32/testapp/build/vs_2008/testapp.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 91 | 99 | 102 | 105 | 108 | 111 | 114 | 126 | 129 | 132 | 135 | 144 | 147 | 150 | 153 | 156 | 159 | 162 | 165 | 166 | 167 | 168 | 169 | 170 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /win32/testapp/build/vs_2012/testapp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testapp", "testapp.vcxproj", "{2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Debug|Win32.ActiveCfg = Release|Win32 15 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Debug|Win32.Build.0 = Release|Win32 16 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Debug|x64.ActiveCfg = Release|x64 17 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Debug|x64.Build.0 = Release|x64 18 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Release|Win32.ActiveCfg = Release|Win32 19 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Release|Win32.Build.0 = Release|Win32 20 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Release|x64.ActiveCfg = Release|x64 21 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /win32/testapp/build/vs_2012/testapp.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {2A6C8427-1CFF-448B-AB3E-0B91BB08FE4A} 23 | Win32Proj 24 | testapp 25 | 26 | 27 | 28 | Application 29 | true 30 | v110 31 | Unicode 32 | 33 | 34 | Application 35 | true 36 | v110 37 | Unicode 38 | 39 | 40 | Application 41 | false 42 | v110 43 | true 44 | Unicode 45 | 46 | 47 | Application 48 | false 49 | v110 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | ..\..\bin\ 72 | 73 | 74 | true 75 | ..\..\bin\x64\ 76 | 77 | 78 | false 79 | ..\..\bin\ 80 | 81 | 82 | false 83 | ..\..\bin\x64\ 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | ..\..\..\driver\include 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | ..\..\..\driver\include 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | 117 | 118 | MaxSpeed 119 | true 120 | true 121 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | ..\..\..\driver\include 123 | 124 | 125 | Console 126 | true 127 | true 128 | true 129 | 130 | 131 | 132 | 133 | Level3 134 | 135 | 136 | MaxSpeed 137 | true 138 | true 139 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 140 | ..\..\..\driver\include 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /win32/testapp/build/vs_2012/testapp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /win32/testapp/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LWCloneU2 3 | * Copyright (C) 2013 Andreas Dittrich 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; 7 | * either version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | 26 | #define LEDWIZ_DLL_NAME "ledwiz.dll" 27 | 28 | 29 | struct { 30 | 31 | struct { 32 | void (LWZCALL * LWZ_SBA) (LWZHANDLE hlwz, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t gps); 33 | void (LWZCALL * LWZ_PBA) (LWZHANDLE hlwz, uint8_t const *pmode32bytes); 34 | void (LWZCALL * LWZ_REGISTER) (LWZHANDLE hlwz, void * hwnd); 35 | void (LWZCALL * LWZ_SET_NOTIFY) (LWZNOTIFYPROC notify_callback, LWZDEVICELIST *plist); 36 | } fn; 37 | 38 | HMODULE hdll; 39 | HWND hwnd; 40 | HANDLE hthread; 41 | 42 | LWZDEVICELIST devlist; 43 | 44 | } g_main; 45 | 46 | 47 | static void CALLBACK notify_cb(int32_t reason, LWZHANDLE hlwz) 48 | { 49 | if (reason == LWZ_REASON_ADD) 50 | { 51 | printf("ledwiz device found, id: %d\n", hlwz); 52 | 53 | g_main.fn.LWZ_REGISTER(hlwz, g_main.hwnd); 54 | 55 | // switch on all LEDs and set brightness to '30' 56 | 57 | g_main.fn.LWZ_SBA(hlwz, 0xFF, 0xFF, 0xFF, 0xFF, 2); 58 | 59 | uint8_t mode[32]; 60 | memset(&mode, 30, sizeof(mode)); 61 | g_main.fn.LWZ_PBA(hlwz, mode); 62 | } 63 | else if (reason == LWZ_REASON_DELETE) 64 | { 65 | printf("ledwiz device removed, id: %d\n", hlwz); 66 | } 67 | } 68 | 69 | static LRESULT CALLBACK MyWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 70 | { 71 | switch (message) 72 | { 73 | case WM_CREATE: 74 | { 75 | // save windows handle 76 | 77 | g_main.hwnd = hwnd; 78 | 79 | // enumerate LED wiz devices 80 | 81 | g_main.fn.LWZ_SET_NOTIFY(notify_cb, &g_main.devlist); 82 | 83 | if (g_main.devlist.numdevices <= 0) 84 | { 85 | printf("no ledwiz devices detected!\n"); 86 | DestroyWindow(hwnd); 87 | return 0; 88 | } 89 | 90 | break; 91 | } 92 | 93 | case WM_CLOSE: 94 | { 95 | // switch off all LEDs for all devices 96 | 97 | for (int i = 0; i < g_main.devlist.numdevices; i++) 98 | { 99 | g_main.fn.LWZ_SBA(g_main.devlist.handles[i], 0x00, 0x00, 0x00, 0x00, 2); 100 | } 101 | 102 | DestroyWindow(hwnd); 103 | return 0; 104 | } 105 | 106 | case WM_DESTROY: 107 | PostQuitMessage(0); 108 | return 0; 109 | } 110 | 111 | return DefWindowProc(hwnd, message, wParam, lParam); 112 | } 113 | 114 | static BOOL ctrlhandler(DWORD fdwCtrlType) 115 | { 116 | switch(fdwCtrlType) 117 | { 118 | case CTRL_C_EVENT: 119 | case CTRL_CLOSE_EVENT: 120 | PostMessage(g_main.hwnd, WM_CLOSE, 0, 0); 121 | WaitForSingleObject(g_main.hthread, INFINITE); 122 | return TRUE; 123 | 124 | default: 125 | return FALSE; 126 | } 127 | } 128 | 129 | static DWORD WINAPI MyThreadProc(LPVOID lpParameter) 130 | { 131 | // load the ledwiz.dll 132 | 133 | g_main.hdll = LoadLibraryA(LEDWIZ_DLL_NAME); 134 | 135 | if (g_main.hdll == NULL) 136 | { 137 | printf("loading " LEDWIZ_DLL_NAME " failed!\n"); 138 | return 0; 139 | } 140 | 141 | ((void**)&g_main.fn.LWZ_SBA)[0] = GetProcAddress(g_main.hdll, "LWZ_SBA"); 142 | ((void**)&g_main.fn.LWZ_PBA)[0] = GetProcAddress(g_main.hdll, "LWZ_PBA"); 143 | ((void**)&g_main.fn.LWZ_REGISTER)[0] = GetProcAddress(g_main.hdll, "LWZ_REGISTER"); 144 | ((void**)&g_main.fn.LWZ_SET_NOTIFY)[0] = GetProcAddress(g_main.hdll, "LWZ_SET_NOTIFY"); 145 | 146 | if (g_main.fn.LWZ_SBA == NULL || 147 | g_main.fn.LWZ_PBA == NULL || 148 | g_main.fn.LWZ_REGISTER == NULL || 149 | g_main.fn.LWZ_SET_NOTIFY == NULL) 150 | { 151 | printf("getting the function addresses failed!\n"); 152 | goto Failed; 153 | } 154 | 155 | // create a hidden window, so we get a 'HWND' for the ledwiz driver and 156 | // we can do the other stuff from the window proc 157 | { 158 | WNDCLASSEXA wx = {}; 159 | wx.cbSize = sizeof(WNDCLASSEXA); 160 | wx.lpfnWndProc = MyWndProc; 161 | wx.hInstance = GetModuleHandle(NULL); 162 | wx.lpszClassName = "LWCloneU2"; 163 | 164 | if (!RegisterClassExA(&wx)) 165 | goto Failed; 166 | 167 | HWND hwnd = CreateWindowExA(0, wx.lpszClassName, "LWCloneU2 TestApp Hidden Window", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 168 | 169 | if (hwnd == NULL) 170 | goto Failed; 171 | } 172 | 173 | // set the console handler to handle the crtl-c and exit clicks 174 | 175 | SetConsoleCtrlHandler((PHANDLER_ROUTINE)ctrlhandler, TRUE); 176 | 177 | printf("waiting for device attachment or removal.\n"); 178 | printf("press to exit\n"); 179 | 180 | // window message loop 181 | 182 | MSG msg; 183 | 184 | while (GetMessage(&msg, NULL, 0, 0)) 185 | { 186 | TranslateMessage(&msg); 187 | DispatchMessage(&msg); 188 | } 189 | 190 | Failed: 191 | if (g_main.hdll) 192 | { 193 | FreeLibrary(g_main.hdll); 194 | g_main.hdll = NULL; 195 | } 196 | 197 | return 0; 198 | } 199 | 200 | int main(int argc, char* argv[]) 201 | { 202 | // create a worker thread (for creating a hidden window) and wait until it exits 203 | 204 | g_main.hthread = CreateThread(NULL, 0, MyThreadProc, NULL, 0, NULL); 205 | 206 | if (g_main.hthread == NULL) 207 | return -1; 208 | 209 | WaitForSingleObject(g_main.hthread, INFINITE); 210 | CloseHandle(g_main.hthread); 211 | } 212 | --------------------------------------------------------------------------------