Erste CVS-Version
This commit is contained in:
		
							
								
								
									
										346
									
								
								License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								License.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,346 @@
 | 
				
			|||||||
 | 
					The following license applies to all but the firmware/usbdrv directories. For
 | 
				
			||||||
 | 
					that directory, please refer to the firmware/usbdrv/License.txt file for
 | 
				
			||||||
 | 
					additional license restrictions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
							       Version 2, June 1991
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					 Everyone is permitted to copy and distribute verbatim copies
 | 
				
			||||||
 | 
					 of this license document, but changing it is not allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    Preamble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The licenses for most software are designed to take away your
 | 
				
			||||||
 | 
					freedom to share and change it.  By contrast, the GNU General Public
 | 
				
			||||||
 | 
					License is intended to guarantee your freedom to share and change free
 | 
				
			||||||
 | 
					software--to make sure the software is free for all its users.  This
 | 
				
			||||||
 | 
					General Public License applies to most of the Free Software
 | 
				
			||||||
 | 
					Foundation's software and to any other program whose authors commit to
 | 
				
			||||||
 | 
					using it.  (Some other Free Software Foundation software is covered by
 | 
				
			||||||
 | 
					the GNU Library General Public License instead.)  You can apply it to
 | 
				
			||||||
 | 
					your programs, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  When we speak of free software, we are referring to freedom, not
 | 
				
			||||||
 | 
					price.  Our General Public Licenses are designed to make sure that you
 | 
				
			||||||
 | 
					have the freedom to distribute copies of free software (and charge for
 | 
				
			||||||
 | 
					this service if you wish), that you receive source code or can get it
 | 
				
			||||||
 | 
					if you want it, that you can change the software or use pieces of it
 | 
				
			||||||
 | 
					in new free programs; and that you know you can do these things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To protect your rights, we need to make restrictions that forbid
 | 
				
			||||||
 | 
					anyone to deny you these rights or to ask you to surrender the rights.
 | 
				
			||||||
 | 
					These restrictions translate to certain responsibilities for you if you
 | 
				
			||||||
 | 
					distribute copies of the software, or if you modify it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  For example, if you distribute copies of such a program, whether
 | 
				
			||||||
 | 
					gratis or for a fee, you must give the recipients all the rights that
 | 
				
			||||||
 | 
					you have.  You must make sure that they, too, receive or can get the
 | 
				
			||||||
 | 
					source code.  And you must show them these terms so they know their
 | 
				
			||||||
 | 
					rights.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  We protect your rights with two steps: (1) copyright the software, and
 | 
				
			||||||
 | 
					(2) offer you this license which gives you legal permission to copy,
 | 
				
			||||||
 | 
					distribute and/or modify the software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Also, for each author's protection and ours, we want to make certain
 | 
				
			||||||
 | 
					that everyone understands that there is no warranty for this free
 | 
				
			||||||
 | 
					software.  If the software is modified by someone else and passed on, we
 | 
				
			||||||
 | 
					want its recipients to know that what they have is not the original, so
 | 
				
			||||||
 | 
					that any problems introduced by others will not reflect on the original
 | 
				
			||||||
 | 
					authors' reputations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Finally, any free program is threatened constantly by software
 | 
				
			||||||
 | 
					patents.  We wish to avoid the danger that redistributors of a free
 | 
				
			||||||
 | 
					program will individually obtain patent licenses, in effect making the
 | 
				
			||||||
 | 
					program proprietary.  To prevent this, we have made it clear that any
 | 
				
			||||||
 | 
					patent must be licensed for everyone's free use or not licensed at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The precise terms and conditions for copying, distribution and
 | 
				
			||||||
 | 
					modification follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  0. This License applies to any program or other work which contains
 | 
				
			||||||
 | 
					a notice placed by the copyright holder saying it may be distributed
 | 
				
			||||||
 | 
					under the terms of this General Public License.  The "Program", below,
 | 
				
			||||||
 | 
					refers to any such program or work, and a "work based on the Program"
 | 
				
			||||||
 | 
					means either the Program or any derivative work under copyright law:
 | 
				
			||||||
 | 
					that is to say, a work containing the Program or a portion of it,
 | 
				
			||||||
 | 
					either verbatim or with modifications and/or translated into another
 | 
				
			||||||
 | 
					language.  (Hereinafter, translation is included without limitation in
 | 
				
			||||||
 | 
					the term "modification".)  Each licensee is addressed as "you".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Activities other than copying, distribution and modification are not
 | 
				
			||||||
 | 
					covered by this License; they are outside its scope.  The act of
 | 
				
			||||||
 | 
					running the Program is not restricted, and the output from the Program
 | 
				
			||||||
 | 
					is covered only if its contents constitute a work based on the
 | 
				
			||||||
 | 
					Program (independent of having been made by running the Program).
 | 
				
			||||||
 | 
					Whether that is true depends on what the Program does.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1. You may copy and distribute verbatim copies of the Program's
 | 
				
			||||||
 | 
					source code as you receive it, in any medium, provided that you
 | 
				
			||||||
 | 
					conspicuously and appropriately publish on each copy an appropriate
 | 
				
			||||||
 | 
					copyright notice and disclaimer of warranty; keep intact all the
 | 
				
			||||||
 | 
					notices that refer to this License and to the absence of any warranty;
 | 
				
			||||||
 | 
					and give any other recipients of the Program a copy of this License
 | 
				
			||||||
 | 
					along with the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You may charge a fee for the physical act of transferring a copy, and
 | 
				
			||||||
 | 
					you may at your option offer warranty protection in exchange for a fee.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  2. You may modify your copy or copies of the Program or any portion
 | 
				
			||||||
 | 
					of it, thus forming a work based on the Program, and copy and
 | 
				
			||||||
 | 
					distribute such modifications or work under the terms of Section 1
 | 
				
			||||||
 | 
					above, provided that you also meet all of these conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) You must cause the modified files to carry prominent notices
 | 
				
			||||||
 | 
					    stating that you changed the files and the date of any change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) You must cause any work that you distribute or publish, that in
 | 
				
			||||||
 | 
					    whole or in part contains or is derived from the Program or any
 | 
				
			||||||
 | 
					    part thereof, to be licensed as a whole at no charge to all third
 | 
				
			||||||
 | 
					    parties under the terms of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) If the modified program normally reads commands interactively
 | 
				
			||||||
 | 
					    when run, you must cause it, when started running for such
 | 
				
			||||||
 | 
					    interactive use in the most ordinary way, to print or display an
 | 
				
			||||||
 | 
					    announcement including an appropriate copyright notice and a
 | 
				
			||||||
 | 
					    notice that there is no warranty (or else, saying that you provide
 | 
				
			||||||
 | 
					    a warranty) and that users may redistribute the program under
 | 
				
			||||||
 | 
					    these conditions, and telling the user how to view a copy of this
 | 
				
			||||||
 | 
					    License.  (Exception: if the Program itself is interactive but
 | 
				
			||||||
 | 
					    does not normally print such an announcement, your work based on
 | 
				
			||||||
 | 
					    the Program is not required to print an announcement.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These requirements apply to the modified work as a whole.  If
 | 
				
			||||||
 | 
					identifiable sections of that work are not derived from the Program,
 | 
				
			||||||
 | 
					and can be reasonably considered independent and separate works in
 | 
				
			||||||
 | 
					themselves, then this License, and its terms, do not apply to those
 | 
				
			||||||
 | 
					sections when you distribute them as separate works.  But when you
 | 
				
			||||||
 | 
					distribute the same sections as part of a whole which is a work based
 | 
				
			||||||
 | 
					on the Program, the distribution of the whole must be on the terms of
 | 
				
			||||||
 | 
					this License, whose permissions for other licensees extend to the
 | 
				
			||||||
 | 
					entire whole, and thus to each and every part regardless of who wrote it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thus, it is not the intent of this section to claim rights or contest
 | 
				
			||||||
 | 
					your rights to work written entirely by you; rather, the intent is to
 | 
				
			||||||
 | 
					exercise the right to control the distribution of derivative or
 | 
				
			||||||
 | 
					collective works based on the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, mere aggregation of another work not based on the Program
 | 
				
			||||||
 | 
					with the Program (or with a work based on the Program) on a volume of
 | 
				
			||||||
 | 
					a storage or distribution medium does not bring the other work under
 | 
				
			||||||
 | 
					the scope of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  3. You may copy and distribute the Program (or a work based on it,
 | 
				
			||||||
 | 
					under Section 2) in object code or executable form under the terms of
 | 
				
			||||||
 | 
					Sections 1 and 2 above provided that you also do one of the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) Accompany it with the complete corresponding machine-readable
 | 
				
			||||||
 | 
					    source code, which must be distributed under the terms of Sections
 | 
				
			||||||
 | 
					    1 and 2 above on a medium customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) Accompany it with a written offer, valid for at least three
 | 
				
			||||||
 | 
					    years, to give any third party, for a charge no more than your
 | 
				
			||||||
 | 
					    cost of physically performing source distribution, a complete
 | 
				
			||||||
 | 
					    machine-readable copy of the corresponding source code, to be
 | 
				
			||||||
 | 
					    distributed under the terms of Sections 1 and 2 above on a medium
 | 
				
			||||||
 | 
					    customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) Accompany it with the information you received as to the offer
 | 
				
			||||||
 | 
					    to distribute corresponding source code.  (This alternative is
 | 
				
			||||||
 | 
					    allowed only for noncommercial distribution and only if you
 | 
				
			||||||
 | 
					    received the program in object code or executable form with such
 | 
				
			||||||
 | 
					    an offer, in accord with Subsection b above.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code for a work means the preferred form of the work for
 | 
				
			||||||
 | 
					making modifications to it.  For an executable work, complete source
 | 
				
			||||||
 | 
					code means all the source code for all modules it contains, plus any
 | 
				
			||||||
 | 
					associated interface definition files, plus the scripts used to
 | 
				
			||||||
 | 
					control compilation and installation of the executable.  However, as a
 | 
				
			||||||
 | 
					special exception, the source code distributed need not include
 | 
				
			||||||
 | 
					anything that is normally distributed (in either source or binary
 | 
				
			||||||
 | 
					form) with the major components (compiler, kernel, and so on) of the
 | 
				
			||||||
 | 
					operating system on which the executable runs, unless that component
 | 
				
			||||||
 | 
					itself accompanies the executable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If distribution of executable or object code is made by offering
 | 
				
			||||||
 | 
					access to copy from a designated place, then offering equivalent
 | 
				
			||||||
 | 
					access to copy the source code from the same place counts as
 | 
				
			||||||
 | 
					distribution of the source code, even though third parties are not
 | 
				
			||||||
 | 
					compelled to copy the source along with the object code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  4. You may not copy, modify, sublicense, or distribute the Program
 | 
				
			||||||
 | 
					except as expressly provided under this License.  Any attempt
 | 
				
			||||||
 | 
					otherwise to copy, modify, sublicense or distribute the Program is
 | 
				
			||||||
 | 
					void, and will automatically terminate your rights under this License.
 | 
				
			||||||
 | 
					However, parties who have received copies, or rights, from you under
 | 
				
			||||||
 | 
					this License will not have their licenses terminated so long as such
 | 
				
			||||||
 | 
					parties remain in full compliance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  5. You are not required to accept this License, since you have not
 | 
				
			||||||
 | 
					signed it.  However, nothing else grants you permission to modify or
 | 
				
			||||||
 | 
					distribute the Program or its derivative works.  These actions are
 | 
				
			||||||
 | 
					prohibited by law if you do not accept this License.  Therefore, by
 | 
				
			||||||
 | 
					modifying or distributing the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), you indicate your acceptance of this License to do so, and
 | 
				
			||||||
 | 
					all its terms and conditions for copying, distributing or modifying
 | 
				
			||||||
 | 
					the Program or works based on it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  6. Each time you redistribute the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), the recipient automatically receives a license from the
 | 
				
			||||||
 | 
					original licensor to copy, distribute or modify the Program subject to
 | 
				
			||||||
 | 
					these terms and conditions.  You may not impose any further
 | 
				
			||||||
 | 
					restrictions on the recipients' exercise of the rights granted herein.
 | 
				
			||||||
 | 
					You are not responsible for enforcing compliance by third parties to
 | 
				
			||||||
 | 
					this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  7. If, as a consequence of a court judgment or allegation of patent
 | 
				
			||||||
 | 
					infringement or for any other reason (not limited to patent issues),
 | 
				
			||||||
 | 
					conditions are imposed on you (whether by court order, agreement or
 | 
				
			||||||
 | 
					otherwise) that contradict the conditions of this License, they do not
 | 
				
			||||||
 | 
					excuse you from the conditions of this License.  If you cannot
 | 
				
			||||||
 | 
					distribute so as to satisfy simultaneously your obligations under this
 | 
				
			||||||
 | 
					License and any other pertinent obligations, then as a consequence you
 | 
				
			||||||
 | 
					may not distribute the Program at all.  For example, if a patent
 | 
				
			||||||
 | 
					license would not permit royalty-free redistribution of the Program by
 | 
				
			||||||
 | 
					all those who receive copies directly or indirectly through you, then
 | 
				
			||||||
 | 
					the only way you could satisfy both it and this License would be to
 | 
				
			||||||
 | 
					refrain entirely from distribution of the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If any portion of this section is held invalid or unenforceable under
 | 
				
			||||||
 | 
					any particular circumstance, the balance of the section is intended to
 | 
				
			||||||
 | 
					apply and the section as a whole is intended to apply in other
 | 
				
			||||||
 | 
					circumstances.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is not the purpose of this section to induce you to infringe any
 | 
				
			||||||
 | 
					patents or other property right claims or to contest validity of any
 | 
				
			||||||
 | 
					such claims; this section has the sole purpose of protecting the
 | 
				
			||||||
 | 
					integrity of the free software distribution system, which is
 | 
				
			||||||
 | 
					implemented by public license practices.  Many people have made
 | 
				
			||||||
 | 
					generous contributions to the wide range of software distributed
 | 
				
			||||||
 | 
					through that system in reliance on consistent application of that
 | 
				
			||||||
 | 
					system; it is up to the author/donor to decide if he or she is willing
 | 
				
			||||||
 | 
					to distribute software through any other system and a licensee cannot
 | 
				
			||||||
 | 
					impose that choice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section is intended to make thoroughly clear what is believed to
 | 
				
			||||||
 | 
					be a consequence of the rest of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  8. If the distribution and/or use of the Program is restricted in
 | 
				
			||||||
 | 
					certain countries either by patents or by copyrighted interfaces, the
 | 
				
			||||||
 | 
					original copyright holder who places the Program under this License
 | 
				
			||||||
 | 
					may add an explicit geographical distribution limitation excluding
 | 
				
			||||||
 | 
					those countries, so that distribution is permitted only in or among
 | 
				
			||||||
 | 
					countries not thus excluded.  In such case, this License incorporates
 | 
				
			||||||
 | 
					the limitation as if written in the body of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  9. The Free Software Foundation may publish revised and/or new versions
 | 
				
			||||||
 | 
					of the General Public License from time to time.  Such new versions will
 | 
				
			||||||
 | 
					be similar in spirit to the present version, but may differ in detail to
 | 
				
			||||||
 | 
					address new problems or concerns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each version is given a distinguishing version number.  If the Program
 | 
				
			||||||
 | 
					specifies a version number of this License which applies to it and "any
 | 
				
			||||||
 | 
					later version", you have the option of following the terms and conditions
 | 
				
			||||||
 | 
					either of that version or of any later version published by the Free
 | 
				
			||||||
 | 
					Software Foundation.  If the Program does not specify a version number of
 | 
				
			||||||
 | 
					this License, you may choose any version ever published by the Free Software
 | 
				
			||||||
 | 
					Foundation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  10. If you wish to incorporate parts of the Program into other free
 | 
				
			||||||
 | 
					programs whose distribution conditions are different, write to the author
 | 
				
			||||||
 | 
					to ask for permission.  For software which is copyrighted by the Free
 | 
				
			||||||
 | 
					Software Foundation, write to the Free Software Foundation; we sometimes
 | 
				
			||||||
 | 
					make exceptions for this.  Our decision will be guided by the two goals
 | 
				
			||||||
 | 
					of preserving the free status of all derivatives of our free software and
 | 
				
			||||||
 | 
					of promoting the sharing and reuse of software generally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    NO WARRANTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
				
			||||||
 | 
					FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
				
			||||||
 | 
					OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
				
			||||||
 | 
					PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
				
			||||||
 | 
					OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
				
			||||||
 | 
					TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
				
			||||||
 | 
					PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
				
			||||||
 | 
					REPAIR OR CORRECTION.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
				
			||||||
 | 
					WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
				
			||||||
 | 
					REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
				
			||||||
 | 
					INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
				
			||||||
 | 
					OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
				
			||||||
 | 
					TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
				
			||||||
 | 
					YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
				
			||||||
 | 
					PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
				
			||||||
 | 
					POSSIBILITY OF SUCH DAMAGES.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							     END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    How to Apply These Terms to Your New Programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  If you develop a new program, and you want it to be of the greatest
 | 
				
			||||||
 | 
					possible use to the public, the best way to achieve this is to make it
 | 
				
			||||||
 | 
					free software which everyone can redistribute and change under these terms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To do so, attach the following notices to the program.  It is safest
 | 
				
			||||||
 | 
					to attach them to the start of each source file to most effectively
 | 
				
			||||||
 | 
					convey the exclusion of warranty; and each file should have at least
 | 
				
			||||||
 | 
					the "copyright" line and a pointer to where the full notice is found.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <one line to give the program's name and a brief idea of what it does.>
 | 
				
			||||||
 | 
					    Copyright (C) <year>  <name of author>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					    the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					    (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					    GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					    along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also add information on how to contact you by electronic and paper mail.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the program is interactive, make it output a short notice like this
 | 
				
			||||||
 | 
					when it starts in an interactive mode:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Gnomovision version 69, Copyright (C) year name of author
 | 
				
			||||||
 | 
					    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
				
			||||||
 | 
					    This is free software, and you are welcome to redistribute it
 | 
				
			||||||
 | 
					    under certain conditions; type `show c' for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The hypothetical commands `show w' and `show c' should show the appropriate
 | 
				
			||||||
 | 
					parts of the General Public License.  Of course, the commands you use may
 | 
				
			||||||
 | 
					be called something other than `show w' and `show c'; they could even be
 | 
				
			||||||
 | 
					mouse-clicks or menu items--whatever suits your program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should also get your employer (if you work as a programmer) or your
 | 
				
			||||||
 | 
					school, if any, to sign a "copyright disclaimer" for the program, if
 | 
				
			||||||
 | 
					necessary.  Here is a sample; alter the names:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 | 
				
			||||||
 | 
					  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <signature of Ty Coon>, 1 April 1989
 | 
				
			||||||
 | 
					  Ty Coon, President of Vice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This General Public License does not permit incorporating your program into
 | 
				
			||||||
 | 
					proprietary programs.  If your program is a subroutine library, you may
 | 
				
			||||||
 | 
					consider it more useful to permit linking proprietary applications with the
 | 
				
			||||||
 | 
					library.  If this is what you want to do, use the GNU Library General
 | 
				
			||||||
 | 
					Public License instead of this License.
 | 
				
			||||||
							
								
								
									
										297
									
								
								Readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								Readme.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,297 @@
 | 
				
			|||||||
 | 
					$Id: Readme.txt,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For full documentation and examples, take a look at htmldoc/index.html.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Introduction
 | 
				
			||||||
 | 
					============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The USB-LED-Fader is a device to control a number of LEDs via USB. I built it
 | 
				
			||||||
 | 
					to display the online-status of my internet-connection, the recording-status of
 | 
				
			||||||
 | 
					my videorecorder, and warnings if the available disc-space is low. You can
 | 
				
			||||||
 | 
					imagine an endless number of applications for this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The LEDs are controlled with pulse width modulation (PWM). That way, they are
 | 
				
			||||||
 | 
					not only on or off, it is possible to control the brightness. Included in the
 | 
				
			||||||
 | 
					device is a number of 'waveforms' that can be displayed on the LEDs. That way,
 | 
				
			||||||
 | 
					one LED can display some kind of a sinus- or triangular wave without any
 | 
				
			||||||
 | 
					interaction with the controlling host.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Every LED can be controlled individually, each one can display it's own
 | 
				
			||||||
 | 
					waveforms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can assign three different waves to every LED: two 'eternal' waves (0 & 1).
 | 
				
			||||||
 | 
					They are displayed alternating until anything different is required. The third
 | 
				
			||||||
 | 
					wave (2) is only displayed once, afterwards the device will switch back to
 | 
				
			||||||
 | 
					alternating between the first two waves.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					One wave is described by three parameters: the waveform, the duration for one
 | 
				
			||||||
 | 
					repetition of the wave and the number of repetitions before switching to the
 | 
				
			||||||
 | 
					next wave.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This version supports four LEDs, it should be quite easy to change that number
 | 
				
			||||||
 | 
					between one and eight. I have not tested any number greater than four, but I
 | 
				
			||||||
 | 
					can imagine that the load on the controller can be too high to reliably
 | 
				
			||||||
 | 
					communicate via USB.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are three parts included in the distribution: The firmware for an ATmega8
 | 
				
			||||||
 | 
					microcontroller, a commandline-client that can be run under Linux, and the
 | 
				
			||||||
 | 
					circuits needed to build the device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This project is based on the PowerSwitch example application by Objective
 | 
				
			||||||
 | 
					Development. Like that, it uses Objective Development's firmware-only USB
 | 
				
			||||||
 | 
					driver for Atmel's AVR microcontrollers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Objective Development's USB driver is a firmware-only implementation of the USB
 | 
				
			||||||
 | 
					1.1 standard (low speed device) on cheap single chip microcomputers of Atmel's
 | 
				
			||||||
 | 
					AVR series, such as the ATtiny2313 or even some of the small 8 pin devices. It
 | 
				
			||||||
 | 
					implements the standard to the point where useful applications can be
 | 
				
			||||||
 | 
					implemented. See the file "firmware/usbdrv/usbdrv.h" for features and
 | 
				
			||||||
 | 
					limitations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Building and installing
 | 
				
			||||||
 | 
					=======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Both, the firmware and Unix command line tool are built with "make". You may
 | 
				
			||||||
 | 
					need to customize both makefiles.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Firmware
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The firmware for this project requires avr-gcc and avr-libc (a C-library for
 | 
				
			||||||
 | 
					the AVR controller). Please read the instructions at
 | 
				
			||||||
 | 
					http://www.nongnu.org/avr-libc/user-manual/install_tools.html for how to
 | 
				
			||||||
 | 
					install the GNU toolchain (avr-gcc, assembler, linker etc.) and avr-libc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once you have the GNU toolchain for AVR microcontrollers installed, you can run
 | 
				
			||||||
 | 
					"make" in the subdirectory "firmware". You may have to edit the Makefile to use
 | 
				
			||||||
 | 
					your preferred downloader with "make program". The current version is built for
 | 
				
			||||||
 | 
					avrdude with a parallel connection to an stk200-compatible programmer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If working with a brand-new controller, you may have to set the fuse-bits to
 | 
				
			||||||
 | 
					use the external crystal:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 avrdude -p atmega8 -P /dev/parport0 -c sp12 -U hfuse:w:0xC9:m \
 | 
				
			||||||
 | 
					                                             -U lfuse:w:0x9F:m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Afterwards, you can compile and flash to the device:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 make program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Commandline client
 | 
				
			||||||
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The command line tool requires libusb. Please download libusb from
 | 
				
			||||||
 | 
					http://libusb.sourceforge.net/ and install it before you compile. Change to
 | 
				
			||||||
 | 
					directory "commandline", check the Makefile and edit the settings if required
 | 
				
			||||||
 | 
					and type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 make
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will build the unix executable "usb-led-fader" which can be used to
 | 
				
			||||||
 | 
					control the device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Usage
 | 
				
			||||||
 | 
					=====
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Connect the device to the USB-port. All LED should flash up to indicate that
 | 
				
			||||||
 | 
					the device is initialized.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then use the commandline-client as follows:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 usb-led-fader status
 | 
				
			||||||
 | 
					 usb-led-fader set <ledId> <waveId> <waveformId> <periodDuration> <repetitionCount>
 | 
				
			||||||
 | 
					 usb-led-fader clear <ledId>
 | 
				
			||||||
 | 
					 usb-led-fader reset
 | 
				
			||||||
 | 
					 usb-led-fader show <waveformId>
 | 
				
			||||||
 | 
					 usb-led-fader test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When using the set-function, it is possible to define several waves at once.
 | 
				
			||||||
 | 
					You simply have to give the parameters for all waves. See examples below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Parameters
 | 
				
			||||||
 | 
					----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ledId: ID of the LED (0-n, depending on the number of LEDs in your circuit).
 | 
				
			||||||
 | 
					- waveId: ID of the wave (0-1: constant waves, 2: override).
 | 
				
			||||||
 | 
					- waveformId: ID of the waveform (0-31: brightness, 32-37: patterns). For a
 | 
				
			||||||
 | 
					  reference to the patterns, consult the function fade_calculateWaveform() in
 | 
				
			||||||
 | 
					  the file "firmware/main.c".
 | 
				
			||||||
 | 
					- periodDuration: Time in sec/10 for one repetition of the waveform. A value of
 | 
				
			||||||
 | 
					  0 can be used to reset the wave.
 | 
				
			||||||
 | 
					- repetitionCount: Number of repetitions before switching to the next wave. A
 | 
				
			||||||
 | 
					  value of 0 can be used to repeat this forever.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Examples
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Get the status of all LEDs:
 | 
				
			||||||
 | 
					 usb-led-fader status
 | 
				
			||||||
 | 
					This will result in an output similar to this:
 | 
				
			||||||
 | 
					 LED 0           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					                     0          2         26          0         23
 | 
				
			||||||
 | 
					       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					          0         38         32          1         20         45
 | 
				
			||||||
 | 
					          1          0          1          1          0          1
 | 
				
			||||||
 | 
					          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 LED 1           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					                     0         14         19          0         19
 | 
				
			||||||
 | 
					       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					          0         38         32          1         20         45
 | 
				
			||||||
 | 
					          1          0          1          1          0          1
 | 
				
			||||||
 | 
					          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 LED 2           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					                     0         31         16          0         43
 | 
				
			||||||
 | 
					       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					          0         38         32          1         20         45
 | 
				
			||||||
 | 
					          1          0          1          1          0          1
 | 
				
			||||||
 | 
					          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 LED 3           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					                     0          6          9          0         39
 | 
				
			||||||
 | 
					       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					          0         38         32          1         20         45
 | 
				
			||||||
 | 
					          1          0          1          1          0          1
 | 
				
			||||||
 | 
					          2          0          1          1          0          1
 | 
				
			||||||
 | 
					In this output, the values curvalue, curpos, nextupd and updtime are for
 | 
				
			||||||
 | 
					debugging purposes only. They shouldn't be of interest to the common user. The
 | 
				
			||||||
 | 
					meaning of the other values should be clear.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Set the first LED to keep a middle brightness:
 | 
				
			||||||
 | 
					 usb-led-fader set 0 0 15 10 1
 | 
				
			||||||
 | 
					So, on LED 0 the wave 0 is set to waveform 15. It will stay there for one
 | 
				
			||||||
 | 
					second and will be repeated once before switching to the next wave. There is no
 | 
				
			||||||
 | 
					next wave because we didn't define one, so this waveform will stay forever.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Now set a second wave on the first LED, a little brighter than the one
 | 
				
			||||||
 | 
					   before:
 | 
				
			||||||
 | 
					 usb-led-fader set 0 1 25 10 1
 | 
				
			||||||
 | 
					This is wave 1 on LED 0, waveform 25 indicates a constant level of brightness.
 | 
				
			||||||
 | 
					After setting the second wave, it will alternate with the first one after every
 | 
				
			||||||
 | 
					second, because both waves have the same duration and the same number of
 | 
				
			||||||
 | 
					repetitions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Set a third wave on the first LED:
 | 
				
			||||||
 | 
					 usb-led-fader set 0 2 36 20 5
 | 
				
			||||||
 | 
					This sets the third wave (wave 2) on the first LED. Waveform 36 is a nice
 | 
				
			||||||
 | 
					sinus-like wave, so the LED starts to fade. One period of the fading takes 2
 | 
				
			||||||
 | 
					seconds, it is repeated for 5 times. Since this is the third wave, after the
 | 
				
			||||||
 | 
					repetitions the LED returns to alternating between wave 0 and wave 1, this wave
 | 
				
			||||||
 | 
					is discarded.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Set multiple waves at once:
 | 
				
			||||||
 | 
					 usb-led-fader set 0 0 15 10 1 0 1 25 10 1 0 2 36 20 5
 | 
				
			||||||
 | 
					This will set all of the above waves at once. Thus, the first LED will first
 | 
				
			||||||
 | 
					fade the sinus-wave five times, then start alternating between the two
 | 
				
			||||||
 | 
					brightnesses in one-second-rhythm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Clear the first LED:
 | 
				
			||||||
 | 
					 usb-led-fader clear 0
 | 
				
			||||||
 | 
					This will clear all three waves on the first LED.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Reset the device:
 | 
				
			||||||
 | 
					 usb-led-fader reset
 | 
				
			||||||
 | 
					All LEDs will flash once, to indicate that the device is reset and the LEDs are
 | 
				
			||||||
 | 
					working.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Show a waveform on the screen:
 | 
				
			||||||
 | 
					 usb-led-fader show 36
 | 
				
			||||||
 | 
					This will lead to an output like the following:
 | 
				
			||||||
 | 
					 wave 36 - length 64
 | 
				
			||||||
 | 
					 31:                              *****
 | 
				
			||||||
 | 
					 30:                            *********
 | 
				
			||||||
 | 
					 29:                           ***********
 | 
				
			||||||
 | 
					 28:                         ***************
 | 
				
			||||||
 | 
					 27:                        *****************
 | 
				
			||||||
 | 
					 26:                       *******************
 | 
				
			||||||
 | 
					 25:                       *******************
 | 
				
			||||||
 | 
					 24:                      *********************
 | 
				
			||||||
 | 
					 23:                     ***********************
 | 
				
			||||||
 | 
					 22:                    *************************
 | 
				
			||||||
 | 
					 21:                    *************************
 | 
				
			||||||
 | 
					 20:                   ***************************
 | 
				
			||||||
 | 
					 19:                  *****************************
 | 
				
			||||||
 | 
					 18:                  *****************************
 | 
				
			||||||
 | 
					 17:                 *******************************
 | 
				
			||||||
 | 
					 16:                *********************************
 | 
				
			||||||
 | 
					 15:               ***********************************
 | 
				
			||||||
 | 
					 14:               ***********************************
 | 
				
			||||||
 | 
					 13:              *************************************
 | 
				
			||||||
 | 
					 12:             ***************************************
 | 
				
			||||||
 | 
					 11:             ***************************************
 | 
				
			||||||
 | 
					 10:            *****************************************
 | 
				
			||||||
 | 
					  9:           *******************************************
 | 
				
			||||||
 | 
					  8:          *********************************************
 | 
				
			||||||
 | 
					  7:          *********************************************
 | 
				
			||||||
 | 
					  6:         ***********************************************
 | 
				
			||||||
 | 
					  5:        *************************************************
 | 
				
			||||||
 | 
					  4:      *****************************************************
 | 
				
			||||||
 | 
					  3:     *******************************************************
 | 
				
			||||||
 | 
					  2:   ***********************************************************
 | 
				
			||||||
 | 
					  1: ****************************************************************
 | 
				
			||||||
 | 
					     ================================================================
 | 
				
			||||||
 | 
					Keep in mind that the width of the displayed wave corresponds to the length of
 | 
				
			||||||
 | 
					the waveform. If you display a very simple one like the constant brightness
 | 
				
			||||||
 | 
					levels (0-31), the length is 1. Therefore only one column is displayed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-> Test the device:
 | 
				
			||||||
 | 
					 usb-led-fader test
 | 
				
			||||||
 | 
					This function sends many random numbers to the device. The device returns the
 | 
				
			||||||
 | 
					packages, and the client looks for differences in the sent and the received
 | 
				
			||||||
 | 
					numbers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Drawbacks
 | 
				
			||||||
 | 
					=========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As mentioned above, controlling the PWM for several LEDs is a lot of work for
 | 
				
			||||||
 | 
					one small microcontroller. Speaking the USB protocol is so, either. Both
 | 
				
			||||||
 | 
					combined result in a lot of load on the device, so the communication with the
 | 
				
			||||||
 | 
					device is not 100% reliable. More than 99% though, at least in our tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SO BE WARNED: You should not use this device to control the state of your
 | 
				
			||||||
 | 
					nuclear reactor. If you intend to use it in that way despite of this warning,
 | 
				
			||||||
 | 
					please let me know... ;-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files in the distribution
 | 
				
			||||||
 | 
					=========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Readme.txt: The file you are currently reading.
 | 
				
			||||||
 | 
					- firmware: Source code of the controller firmware.
 | 
				
			||||||
 | 
					- firmware/usbdrv: USB driver -- See Readme.txt in this directory for info
 | 
				
			||||||
 | 
					- commandline: Source code of the host software (needs libusb).
 | 
				
			||||||
 | 
					- common: Files needed by the firmware and the commandline-client.
 | 
				
			||||||
 | 
					- circuit: Circuit diagrams in PDF and EAGLE 4 format. A free version of EAGLE
 | 
				
			||||||
 | 
					  is available for Linux, Mac OS X and Windows from http://www.cadsoft.de/.
 | 
				
			||||||
 | 
					- License.txt: Public license for all contents of this project, except for the
 | 
				
			||||||
 | 
					  USB driver. Look in firmware/usbdrv/License.txt for further info.
 | 
				
			||||||
 | 
					- Changelog.txt: Logfile documenting changes in soft-, firm- and hardware.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thanks!
 | 
				
			||||||
 | 
					=======
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I'd like to thank Objective Development for the possibility to use their driver
 | 
				
			||||||
 | 
					for my project. In fact, this project wouldn't exist without the driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And I'd like to give special credits to Thomas Stegemann. He wrote the
 | 
				
			||||||
 | 
					PWM-stuff, and I guess it would have been nearly to impossible to me to write
 | 
				
			||||||
 | 
					the rest of the project without his help since C isn't my natural language.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					About the license
 | 
				
			||||||
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Our work - all contents except for the USB driver - are licensed under the GNU
 | 
				
			||||||
 | 
					General Public License (GPL). A copy of the GPL is included in License.txt. The
 | 
				
			||||||
 | 
					driver itself is licensed under a special license by Objective Development. See
 | 
				
			||||||
 | 
					firmware/usbdrv/License.txt for further info.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(c) 2006 by Ronald Schaten - http://www.schatenseite.de
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								circuit/circuit.brd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								circuit/circuit.brd
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								circuit/circuit.sch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								circuit/circuit.sch
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										30
									
								
								circuit/partlist.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								circuit/partlist.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					Partlist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Exported from circuit.sch at  9/15/2006 14:21:25 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EAGLE Version 4.16 Copyright (c) 1988-2005 CadSoft
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Part     Value          Device          Package      Library  Sheet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					C1       4,7u           CPOL-EUE2.5-5   E2,5-5       rcl      1
 | 
				
			||||||
 | 
					C2       100n           C-EU025-024X044 C025-024X044 rcl      1
 | 
				
			||||||
 | 
					C3       22p            C-EU025-024X044 C025-024X044 rcl      1
 | 
				
			||||||
 | 
					C4       22p            C-EU025-024X044 C025-024X044 rcl      1
 | 
				
			||||||
 | 
					IC1      MEGA8-P        MEGA8-P         DIL28-3      avr      1
 | 
				
			||||||
 | 
					IC2      LM317LZ        LM317LZ         TO92         linear   1
 | 
				
			||||||
 | 
					JP1      ISP            JP5Q            JP5Q         jumper   1
 | 
				
			||||||
 | 
					LED1                    LED5MM          LED5MM       led      1
 | 
				
			||||||
 | 
					LED2                    LED5MM          LED5MM       led      1
 | 
				
			||||||
 | 
					LED3                    LED5MM          LED5MM       led      1
 | 
				
			||||||
 | 
					LED4                    LED5MM          LED5MM       led      1
 | 
				
			||||||
 | 
					Q1       12MHz          CRYTALHC18U-V   HC18U-V      crystal  1
 | 
				
			||||||
 | 
					R1       432            R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R2       240            R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R3       1k5            R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R4       68             R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R5       68             R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R6       1k             R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R7       1k             R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R8       1k             R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					R9       1k             R-EU_0207/10    0207/10      rcl      1
 | 
				
			||||||
 | 
					X1                      PN61729         PN61729      con-berg 1
 | 
				
			||||||
							
								
								
									
										23
									
								
								commandline/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								commandline/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					# $Id: Makefile,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CC              = gcc
 | 
				
			||||||
 | 
					LIBUSB_CONFIG   = libusb-config
 | 
				
			||||||
 | 
					# Make sure that libusb-config is in the search path or specify a full path. On
 | 
				
			||||||
 | 
					# Windows, there is no libusb-config and you must configure the options below
 | 
				
			||||||
 | 
					# manually. See examples.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS          = `$(LIBUSB_CONFIG) --cflags` -O -Wall -I../common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS            = `$(LIBUSB_CONFIG) --libs`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: usb-led-fader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.c.o:
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) -c $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usb-led-fader: usb-led-fader.o
 | 
				
			||||||
 | 
						$(CC) -o usb-led-fader usb-led-fader.o $(LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -f *.o
 | 
				
			||||||
 | 
						rm -f usb-led-fader
 | 
				
			||||||
							
								
								
									
										426
									
								
								commandline/usb-led-fader.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										426
									
								
								commandline/usb-led-fader.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,426 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file usb-led-fader.c
 | 
				
			||||||
 | 
					 * \brief Commandline-tool for the USB-LED-Fader.
 | 
				
			||||||
 | 
					 * \author Ronald Schaten
 | 
				
			||||||
 | 
					 * \version $Id: usb-led-fader.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <usb.h>                /* this is libusb, see http://libusb.sourceforge.net/ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "usbledfader.h"
 | 
				
			||||||
 | 
					#include "channels.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBDEV_SHARED_VENDOR    0x16C0  /**< VOTI */
 | 
				
			||||||
 | 
					#define USBDEV_SHARED_PRODUCT   0x05DC  /**< Obdev's free shared PID. Use obdev's generic shared VID/PID pair and follow the rules outlined in firmware/usbdrv/USBID-License.txt. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* These are error codes for the communication via USB. */
 | 
				
			||||||
 | 
					#define USB_ERROR_NOTFOUND  1 /**< Error code if the device isn't found. */
 | 
				
			||||||
 | 
					#define USB_ERROR_ACCESS    2 /**< Error code if the device isn't accessible. */
 | 
				
			||||||
 | 
					#define USB_ERROR_IO        3 /**< Error code if errors in the communication with the device occur. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Displays usage-informations. This function is called if the parameters
 | 
				
			||||||
 | 
					 * cannot be parsed.
 | 
				
			||||||
 | 
					 * \param name The name of this application.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void usage(char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fprintf(stderr, "usage:\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "  %s status\n", name);
 | 
				
			||||||
 | 
					    fprintf(stderr, "  %s set ledId waveId waveformId periodDuration repetitionCount\n", name);
 | 
				
			||||||
 | 
					    fprintf(stderr, "  %s clear ledId\n", name);
 | 
				
			||||||
 | 
					    fprintf(stderr, "  %s reset\n", name);
 | 
				
			||||||
 | 
					    fprintf(stderr, "  %s show waveformId\n", name);
 | 
				
			||||||
 | 
					    fprintf(stderr, "  %s test\n\n", name);
 | 
				
			||||||
 | 
					    fprintf(stderr, "parameters:\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "  ledId: ID of the LED (0-%d).\n", CHANNELS - 1);
 | 
				
			||||||
 | 
					    fprintf(stderr, "  waveId: ID of the wave (0-1: constant waves, 2: override).\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "  waveformId: ID of the waveform (0-31: brightness, 32-37: patterns).\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "  periodDuration: Time in sec/10 for one repetition of the waveform.\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "                  A value of 0 can be used to reset the wave.\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "  repetitionCount: Number of repetitions before switching to the next wave.\n");
 | 
				
			||||||
 | 
					    fprintf(stderr, "                   A value of 0 can be used to repeat this forever.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reads and converts a string from USB. The conversion to ASCII is 'lossy' (unknown characters become '?').
 | 
				
			||||||
 | 
					 * \param dev Handle of the USB-Device.
 | 
				
			||||||
 | 
					 * \param index Index of the required data.
 | 
				
			||||||
 | 
					 * \param langid Index of the expected language.
 | 
				
			||||||
 | 
					 * \param buf Buffer to contain the return-string.
 | 
				
			||||||
 | 
					 * \param buflen Length of buf.
 | 
				
			||||||
 | 
					 * \return Length of the string.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbGetStringAscii(usb_dev_handle * dev, int index, int langid, char *buf, int buflen) {
 | 
				
			||||||
 | 
					    char buffer[256];
 | 
				
			||||||
 | 
					    int rval, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0) {
 | 
				
			||||||
 | 
					        return rval;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (buffer[1] != USB_DT_STRING) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if ((unsigned char) buffer[0] < rval) {
 | 
				
			||||||
 | 
					        rval = (unsigned char) buffer[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rval /= 2;
 | 
				
			||||||
 | 
					    /* lossy conversion to ISO Latin1 */
 | 
				
			||||||
 | 
					    for (i = 1; i < rval; i++) {
 | 
				
			||||||
 | 
					        if (i > buflen) {
 | 
				
			||||||
 | 
					            /* destination buffer overflow */
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        buf[i - 1] = buffer[2 * i];
 | 
				
			||||||
 | 
					        if (buffer[2 * i + 1] != 0) {
 | 
				
			||||||
 | 
					            /* outside of ISO Latin1 range */
 | 
				
			||||||
 | 
					            buf[i - 1] = '?';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    buf[i - 1] = 0;
 | 
				
			||||||
 | 
					    return i - 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Connect to the USB-device. Loops through all connected USB-Devices and
 | 
				
			||||||
 | 
					 * searches our counterpart.
 | 
				
			||||||
 | 
					 * \param device Handle to address the device.
 | 
				
			||||||
 | 
					 * \param vendor USBDEV_SHARED_VENDOR as defined.
 | 
				
			||||||
 | 
					 * \param vendorName In our case "www.schatenseite.de".
 | 
				
			||||||
 | 
					 * \param product USBDEV_SHARED_PRODUCT as defined.
 | 
				
			||||||
 | 
					 * \param productName In our case "USB-LED-Fader".
 | 
				
			||||||
 | 
					 * \return Error code.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int usbOpenDevice(usb_dev_handle ** device, int vendor, char *vendorName, int product, char *productName) {
 | 
				
			||||||
 | 
					    struct usb_bus *bus;
 | 
				
			||||||
 | 
					    struct usb_device *dev;
 | 
				
			||||||
 | 
					    usb_dev_handle *handle = NULL;
 | 
				
			||||||
 | 
					    int errorCode = USB_ERROR_NOTFOUND;
 | 
				
			||||||
 | 
					    static int didUsbInit = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!didUsbInit) {
 | 
				
			||||||
 | 
					        didUsbInit = 1;
 | 
				
			||||||
 | 
					        usb_init();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usb_find_busses();
 | 
				
			||||||
 | 
					    usb_find_devices();
 | 
				
			||||||
 | 
					    for (bus = usb_get_busses(); bus; bus = bus->next) {
 | 
				
			||||||
 | 
					        for (dev = bus->devices; dev; dev = dev->next) {
 | 
				
			||||||
 | 
					            if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) {
 | 
				
			||||||
 | 
					                char string[256];
 | 
				
			||||||
 | 
					                int len;
 | 
				
			||||||
 | 
					                handle = usb_open(dev); /* we need to open the device in order to query strings */
 | 
				
			||||||
 | 
					                if (!handle) {
 | 
				
			||||||
 | 
					                    errorCode = USB_ERROR_ACCESS;
 | 
				
			||||||
 | 
					                    fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (vendorName == NULL && productName == NULL) {        /* name does not matter */
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                /* now check whether the names match: */
 | 
				
			||||||
 | 
					                len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
 | 
				
			||||||
 | 
					                if (len < 0) {
 | 
				
			||||||
 | 
					                    errorCode = USB_ERROR_IO;
 | 
				
			||||||
 | 
					                    fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    errorCode = USB_ERROR_NOTFOUND;
 | 
				
			||||||
 | 
					                    /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */
 | 
				
			||||||
 | 
					                    if (strcmp(string, vendorName) == 0) {
 | 
				
			||||||
 | 
					                        len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
 | 
				
			||||||
 | 
					                        if (len < 0) {
 | 
				
			||||||
 | 
					                            errorCode = USB_ERROR_IO;
 | 
				
			||||||
 | 
					                            fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            errorCode = USB_ERROR_NOTFOUND;
 | 
				
			||||||
 | 
					                            /* fprintf(stderr, "seen product ->%s<-\n", string); */
 | 
				
			||||||
 | 
					                            if (strcmp(string, productName) == 0) {
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                usb_close(handle);
 | 
				
			||||||
 | 
					                handle = NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (handle) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (handle != NULL) {
 | 
				
			||||||
 | 
					        errorCode = 0;
 | 
				
			||||||
 | 
					        *device = handle;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return errorCode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Test connection to the device. The test consists of writing 1000 random
 | 
				
			||||||
 | 
					 * numbers to the device and checking the echo. This should discover systematic
 | 
				
			||||||
 | 
					 * bit errors (e.g. in bit stuffing).
 | 
				
			||||||
 | 
					 * \param handle Handle to talk to the device.
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dev_test(usb_dev_handle *handle, int argc, char** argv) {
 | 
				
			||||||
 | 
					    unsigned char buffer[8];
 | 
				
			||||||
 | 
					    int nBytes;
 | 
				
			||||||
 | 
					    int i, v, r;
 | 
				
			||||||
 | 
					    if (argc != 2) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < 1000; i++) {
 | 
				
			||||||
 | 
					        v = rand() & 0xffff;
 | 
				
			||||||
 | 
					        nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_ECHO, v, 0, (char *) buffer, sizeof(buffer), 5000);
 | 
				
			||||||
 | 
					        if (nBytes < 2) {
 | 
				
			||||||
 | 
					            if (nBytes < 0) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "USB error: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            fprintf(stderr, "only %d bytes received in iteration %d\n", nBytes, i);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        r = buffer[0] | (buffer[1] << 8);
 | 
				
			||||||
 | 
					        if (r != v) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "data error: received 0x%x instead of 0x%x in iteration %d\n", r, v, i);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("test succeeded\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set waves. It is possible to set any number of waves at once.
 | 
				
			||||||
 | 
					 * \param handle Handle to talk to the device.
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dev_set(usb_dev_handle *handle, int argc, char** argv) {
 | 
				
			||||||
 | 
					    unsigned char buffer[8];
 | 
				
			||||||
 | 
					    int nBytes;
 | 
				
			||||||
 | 
					    int parameter;
 | 
				
			||||||
 | 
					    if ((argc < 7) || ((argc - 2) % 5 != 0)) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (parameter = 2; (parameter + 4) < argc; parameter += 5) {
 | 
				
			||||||
 | 
					        int ledId = atoi(argv[parameter + 0]);
 | 
				
			||||||
 | 
					        if ((ledId < 0) || (ledId > (CHANNELS - 1))) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "invalid ledId: %d\n", ledId);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int waveId = atoi(argv[parameter + 1]);
 | 
				
			||||||
 | 
					        if ((waveId < 0) || (waveId > 2)) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "invalid waveId: %d\n", waveId);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int waveformId = atoi(argv[parameter + 2]);
 | 
				
			||||||
 | 
					        if ((waveformId < 0) || (waveformId > 38)) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "invalid waveformId: %d\n", waveformId);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int periodDuration = atoi(argv[parameter + 3]);
 | 
				
			||||||
 | 
					        if ((periodDuration < 0) || (periodDuration > 255)) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "invalid periodDuration: %d\n", periodDuration);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int repetitionCount = atoi(argv[parameter + 4]);
 | 
				
			||||||
 | 
					        if ((repetitionCount < 0) || (repetitionCount > 255)) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "invalid repetitionCount: %d\n", repetitionCount);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer[0] = CMD_SET;
 | 
				
			||||||
 | 
					        buffer[1] = ledId;
 | 
				
			||||||
 | 
					        buffer[2] = waveId;
 | 
				
			||||||
 | 
					        buffer[3] = waveformId;
 | 
				
			||||||
 | 
					        buffer[4] = periodDuration;
 | 
				
			||||||
 | 
					        buffer[5] = repetitionCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_SET, ledId, 0, (char *) buffer, sizeof(buffer), 5000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (nBytes < 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "USB error: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clear all waves on one LED.
 | 
				
			||||||
 | 
					 * \param handle Handle to talk to the device.
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dev_clear(usb_dev_handle *handle, int argc, char** argv) {
 | 
				
			||||||
 | 
					    unsigned char buffer[8];
 | 
				
			||||||
 | 
					    int nBytes;
 | 
				
			||||||
 | 
					    if (argc != 3) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int ledId = atoi(argv[2]);
 | 
				
			||||||
 | 
					    if ((ledId < 0) || (ledId > (CHANNELS - 1))) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "invalid LED: %d\n", ledId);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_CLEAR, ledId, 0, (char *) buffer, sizeof(buffer), 5000);
 | 
				
			||||||
 | 
					    if (nBytes < 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "USB error: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the status of the device. Status information is printed in detail.
 | 
				
			||||||
 | 
					 * \param handle Handle to talk to the device.
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dev_status(usb_dev_handle *handle, int argc, char** argv) {
 | 
				
			||||||
 | 
					    int nBytes;
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					    static fade_GlobalData fade_globalData; /* contains the state of all four LEDs. */
 | 
				
			||||||
 | 
					    if (argc != 2) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_GET, 0, 0, (char *) &fade_globalData, sizeof(fade_globalData), 5000);
 | 
				
			||||||
 | 
					    if (nBytes < 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "USB error: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (nBytes != sizeof(fade_globalData)) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "USB oddity: %d bytes received, %d bytes expected.\n", nBytes, sizeof(fade_globalData));
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (i = 0; i < CHANNELS; i++) {
 | 
				
			||||||
 | 
					        printf("LED %d      %10s %10s %10s %10s %10s\n", i, "curid", "curvalue", "curpos", "currep", "nextupd");
 | 
				
			||||||
 | 
					        printf("           %10d %10d %10d %10d %10d\n",
 | 
				
			||||||
 | 
					            fade_globalData.led[i].waveCurrentId,
 | 
				
			||||||
 | 
					            fade_globalData.led[i].waveCurrentValue,
 | 
				
			||||||
 | 
					            fade_globalData.led[i].waveCurrentPosition,
 | 
				
			||||||
 | 
					            fade_globalData.led[i].waveCurrentRepetition,
 | 
				
			||||||
 | 
					            fade_globalData.led[i].waveNextUpdate);
 | 
				
			||||||
 | 
					        printf("%10s %10s %10s %10s %10s %10s\n", "wave", "waveform", "length", "repeat", "duration", "updtime");
 | 
				
			||||||
 | 
					        for (j = 0; j < 3; j++) {
 | 
				
			||||||
 | 
					            printf("%10d %10d %10d %10d %10d %10d\n",
 | 
				
			||||||
 | 
					                j,
 | 
				
			||||||
 | 
					                fade_globalData.led[i].wave[j].waveformId,
 | 
				
			||||||
 | 
					                fade_globalData.led[i].wave[j].waveformLength,
 | 
				
			||||||
 | 
					                fade_globalData.led[i].wave[j].waveformRepetition,
 | 
				
			||||||
 | 
					                fade_globalData.led[i].wave[j].waveformDuration,
 | 
				
			||||||
 | 
					                fade_globalData.led[i].wave[j].waveformUpdateTime);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Reset the device.
 | 
				
			||||||
 | 
					 * \param handle Handle to talk to the device.
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dev_reset(usb_dev_handle *handle, int argc, char** argv) {
 | 
				
			||||||
 | 
					    unsigned char buffer[8];
 | 
				
			||||||
 | 
					    int nBytes;
 | 
				
			||||||
 | 
					    if (argc != 2) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CMD_RESET, 0, 0, (char *) buffer, sizeof(buffer), 5000);
 | 
				
			||||||
 | 
					    if (nBytes < 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "USB error: %s\n", usb_strerror());
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Show a waveform. This will not send a command to the device, the waveform is
 | 
				
			||||||
 | 
					 * only printed on the screen.
 | 
				
			||||||
 | 
					 * \param handle Handle to talk to the device (not needed).
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int dev_show(int argc, char **argv) {
 | 
				
			||||||
 | 
					    if (argc != 3) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int waveformId = atoi(argv[2]);
 | 
				
			||||||
 | 
					    if ((waveformId < 0) || (waveformId > 38)) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "invalid waveformId: %d\n", waveformId);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					    int length = fade_calculateWaveform(waveformId, 0);
 | 
				
			||||||
 | 
					    printf("wave %2d - length %2d\n", waveformId, length);
 | 
				
			||||||
 | 
					    for (i = 31; i > 0; i--) {
 | 
				
			||||||
 | 
					        printf("%2d: ", i);
 | 
				
			||||||
 | 
					        for (j = 1; j <= length; j++) {
 | 
				
			||||||
 | 
					            if (fade_calculateWaveform(waveformId, j) >= i) {
 | 
				
			||||||
 | 
					                printf("*");
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                printf(" ");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        printf("\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("    ");
 | 
				
			||||||
 | 
					    for (j = 1; j <= length; j++) {
 | 
				
			||||||
 | 
					        printf("=");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("\n");
 | 
				
			||||||
 | 
					    exit(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Main function. Initializes the USB-device, parses commandline-parameters and
 | 
				
			||||||
 | 
					 * calls the functions that communicate with the device.
 | 
				
			||||||
 | 
					 * \param argc Number of arguments.
 | 
				
			||||||
 | 
					 * \param argv Arguments.
 | 
				
			||||||
 | 
					 * \return Error code.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    usb_dev_handle *handle = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc < 2) {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usb_init();
 | 
				
			||||||
 | 
					    if (usbOpenDevice (&handle, USBDEV_SHARED_VENDOR, "www.schatenseite.de", USBDEV_SHARED_PRODUCT, "USB-LED-Fader") != 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Could not find USB device \"USB-LED-Fader\" with vid=0x%x pid=0x%x\n", USBDEV_SHARED_VENDOR, USBDEV_SHARED_PRODUCT);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* We have searched all devices on all busses for our USB device above. Now
 | 
				
			||||||
 | 
					     * try to open it and perform the vendor specific control operations for the
 | 
				
			||||||
 | 
					     * function requested by the user.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (strcmp(argv[1], "test") == 0) {
 | 
				
			||||||
 | 
					        dev_test(handle, argc, argv);
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], "set") == 0) {
 | 
				
			||||||
 | 
					        dev_set(handle, argc, argv);
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], "clear") == 0) {
 | 
				
			||||||
 | 
					        dev_clear(handle, argc, argv);
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], "status") == 0) {
 | 
				
			||||||
 | 
					        dev_status(handle, argc, argv);
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], "reset") == 0) {
 | 
				
			||||||
 | 
					        dev_reset(handle, argc, argv);
 | 
				
			||||||
 | 
					    } else if (strcmp(argv[1], "show") == 0) {
 | 
				
			||||||
 | 
					        dev_reset(handle, argc, argv);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        usage(argv[0]);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usb_close(handle);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										16
									
								
								common/channels.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								common/channels.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					#ifndef __channels_h_included__
 | 
				
			||||||
 | 
					#define __channels_h_included__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file channels.h
 | 
				
			||||||
 | 
					 * \brief Global definitions, used by the firmware and the commandline-client.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: channels.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CHANNELS 4 /**< number of output channels */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										466
									
								
								common/usbledfader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								common/usbledfader.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,466 @@
 | 
				
			|||||||
 | 
					#ifndef __usbledfader_h_included__
 | 
				
			||||||
 | 
					#define __usbledfader_h_included__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file usbledfader.h
 | 
				
			||||||
 | 
					 * \brief Global definitions and datatypes, used by the firmware and the commandline-client. Also contains the main doxygen-documentation.
 | 
				
			||||||
 | 
					 * \author Ronald Schaten & Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: usbledfader.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \mainpage USB-LED-Fader
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_intro Introduction
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The USB-LED-Fader is a device to control a number of LEDs via USB. I built
 | 
				
			||||||
 | 
					 * it to display the online-status of my internet-connection, the
 | 
				
			||||||
 | 
					 * recording-status of my videorecorder, and warnings if the available
 | 
				
			||||||
 | 
					 * disc-space is low. You can imagine an endless number of applications for
 | 
				
			||||||
 | 
					 * this.  
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The LEDs are controlled with pulse width modulation (PWM). That way, they
 | 
				
			||||||
 | 
					 * are not only on or off, it is possible to control the brightness. Included
 | 
				
			||||||
 | 
					 * in the device is a number of 'waveforms' that can be displayed on the LEDs.
 | 
				
			||||||
 | 
					 * That way, one LED can display some kind of a sinus- or triangular wave
 | 
				
			||||||
 | 
					 * without any interaction with the controlling host.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Every LED can be controlled individually, each one can display it's own
 | 
				
			||||||
 | 
					 * waveforms.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * You can assign three different waves to every LED: two 'eternal' waves (0 &
 | 
				
			||||||
 | 
					 * 1). They are displayed alternating until anything different is required. The
 | 
				
			||||||
 | 
					 * third wave (2) is only displayed once, afterwards the device will switch
 | 
				
			||||||
 | 
					 * back to alternating between the first two waves.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * One wave is described by three parameters: the waveform, the duration for
 | 
				
			||||||
 | 
					 * one repetition of the wave and the number of repetitions before switching to
 | 
				
			||||||
 | 
					 * the next wave.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This version supports four LEDs, it should be quite easy to change that
 | 
				
			||||||
 | 
					 * number between one and eight. I have not tested any number greater than
 | 
				
			||||||
 | 
					 * four, but I can imagine that the load on the controller can be too high to
 | 
				
			||||||
 | 
					 * reliably communicate via USB.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * There are three parts included in the distribution: The firmware for an
 | 
				
			||||||
 | 
					 * ATmega8 microcontroller, a commandline-client that can be run under Linux,
 | 
				
			||||||
 | 
					 * and the circuits needed to build the device.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This project is based on the PowerSwitch example application by Objective
 | 
				
			||||||
 | 
					 * Development. Like that, it uses Objective Development's firmware-only USB
 | 
				
			||||||
 | 
					 * driver for Atmel's AVR microcontrollers.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Objective Development's USB driver is a firmware-only implementation of the
 | 
				
			||||||
 | 
					 * USB 1.1 standard (low speed device) on cheap single chip microcomputers of
 | 
				
			||||||
 | 
					 * Atmel's AVR series, such as the ATtiny2313 or even some of the small 8 pin
 | 
				
			||||||
 | 
					 * devices. It implements the standard to the point where useful applications
 | 
				
			||||||
 | 
					 * can be implemented. See the file "firmware/usbdrv/usbdrv.h" for features and
 | 
				
			||||||
 | 
					 * limitations.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * \section sec_install Building and installing
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Both, the firmware and Unix command line tool are built with "make". You may
 | 
				
			||||||
 | 
					 * need to customize both makefiles.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * \subsection sec_fw Firmware
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The firmware for this project requires avr-gcc and avr-libc (a C-library for
 | 
				
			||||||
 | 
					 * the AVR controller). Please read the instructions at
 | 
				
			||||||
 | 
					 * http://www.nongnu.org/avr-libc/user-manual/install_tools.html for how to
 | 
				
			||||||
 | 
					 * install the GNU toolchain (avr-gcc, assembler, linker etc.) and avr-libc.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Once you have the GNU toolchain for AVR microcontrollers installed, you can
 | 
				
			||||||
 | 
					 * run "make" in the subdirectory "firmware". You may have to edit the Makefile
 | 
				
			||||||
 | 
					 * to use your preferred downloader with "make program". The current version is
 | 
				
			||||||
 | 
					 * built for avrdude with a parallel connection to an stk200-compatible
 | 
				
			||||||
 | 
					 * programmer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * If working with a brand-new controller, you may have to set the fuse-bits to
 | 
				
			||||||
 | 
					 * use the external crystal:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * avrdude -p atmega8 -P /dev/parport0 -c sp12 -U hfuse:w:0xC9:m -U lfuse:w:0x9F:m
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Afterwards, you can compile and flash to the device:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * make program
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsection sec_client Commandline client
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The command line tool requires libusb. Please take the packages from your
 | 
				
			||||||
 | 
					 * system's distribution or download libusb from http://libusb.sourceforge.net/
 | 
				
			||||||
 | 
					 * and install it before you compile. Change to directory "commandline", check
 | 
				
			||||||
 | 
					 * the Makefile and edit the settings if required and type
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * make
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This will build the unix executable "usb-led-fader" which can be used to
 | 
				
			||||||
 | 
					 * control the device.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_usage Usage
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Connect the device to the USB-port. All LED should flash up to indicate that
 | 
				
			||||||
 | 
					 * the device is initialized.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Then use the commandline-client as follows:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader status
 | 
				
			||||||
 | 
					 * usb-led-fader set <ledId> <waveId> <waveformId> <periodDuration> <repetitionCount>
 | 
				
			||||||
 | 
					 * usb-led-fader clear <ledId>
 | 
				
			||||||
 | 
					 * usb-led-fader reset
 | 
				
			||||||
 | 
					 * usb-led-fader show <waveformId>
 | 
				
			||||||
 | 
					 * usb-led-fader test
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * When using the set-function, it is possible to define several waves at once.
 | 
				
			||||||
 | 
					 * You simply have to give the parameters for all waves. See examples below.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsection sec_params Parameters
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - \e ledId: ID of the LED (0-n, depending on the number of LEDs in your
 | 
				
			||||||
 | 
					 *   circuit).
 | 
				
			||||||
 | 
					 * - \e waveId: ID of the wave (0-1: constant waves, 2: override).
 | 
				
			||||||
 | 
					 * - \e waveformId: ID of the waveform (0-31: brightness, 32-37: patterns). For
 | 
				
			||||||
 | 
					 *   a reference to the patterns, consult the function fade_calculateWaveform()
 | 
				
			||||||
 | 
					 *   in the file "firmware/main.c".
 | 
				
			||||||
 | 
					 * - \e periodDuration: Time in sec/10 for one repetition of the waveform. A
 | 
				
			||||||
 | 
					 *   value of 0 can be used to reset the wave.
 | 
				
			||||||
 | 
					 * - \e repetitionCount: Number of repetitions before switching to the next
 | 
				
			||||||
 | 
					 *   wave.  A value of 0 can be used to repeat this forever.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsection sec_examples Examples
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Get the status of all LEDs:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader status
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This will result in an output similar to this:
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * LED 0           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					 *                     0          2         26          0         23
 | 
				
			||||||
 | 
					 *       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					 *          0         38         32          1         20         45
 | 
				
			||||||
 | 
					 *          1          0          1          1          0          1
 | 
				
			||||||
 | 
					 *          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 * LED 1           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					 *                     0         14         19          0         19
 | 
				
			||||||
 | 
					 *       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					 *          0         38         32          1         20         45
 | 
				
			||||||
 | 
					 *          1          0          1          1          0          1
 | 
				
			||||||
 | 
					 *          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 * LED 2           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					 *                     0         31         16          0         43
 | 
				
			||||||
 | 
					 *       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					 *          0         38         32          1         20         45
 | 
				
			||||||
 | 
					 *          1          0          1          1          0          1
 | 
				
			||||||
 | 
					 *          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 * LED 3           curid   curvalue     curpos     currep    nextupd
 | 
				
			||||||
 | 
					 *                     0          6          9          0         39
 | 
				
			||||||
 | 
					 *       wave   waveform     length     repeat   duration    updtime
 | 
				
			||||||
 | 
					 *          0         38         32          1         20         45
 | 
				
			||||||
 | 
					 *          1          0          1          1          0          1
 | 
				
			||||||
 | 
					 *          2          0          1          1          0          1
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * In this output, the values curvalue, curpos, nextupd and updtime are for
 | 
				
			||||||
 | 
					 * debugging purposes only. They shouldn't be of interest to the common user.
 | 
				
			||||||
 | 
					 * The meaning of the other values should be clear.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Set the first LED to keep a middle brightness:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader set 0 0 15 10 1
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * So, on LED 0 the wave 0 is set to waveform 15. It will stay there for one
 | 
				
			||||||
 | 
					 * second and will be repeated once before switching to the next wave. There is
 | 
				
			||||||
 | 
					 * no next wave because we didn't define one, so this waveform will stay
 | 
				
			||||||
 | 
					 * forever.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Now set a second wave on the first LED, a little brighter than the one
 | 
				
			||||||
 | 
					 * before:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader set 0 1 25 10 1
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This is wave 1 on LED 0, waveform 25 indicates a constant level of
 | 
				
			||||||
 | 
					 * brightness. After setting the second wave, it will alternate with the first
 | 
				
			||||||
 | 
					 * one after every second, because both waves have the same duration and the
 | 
				
			||||||
 | 
					 * same number of repetitions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Set a third wave on the first LED:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader set 0 2 36 20 5
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This sets the third wave (wave 2) on the first LED. Waveform 36 is a nice
 | 
				
			||||||
 | 
					 * sinus-like wave, so the LED starts to fade. One period of the fading takes 2
 | 
				
			||||||
 | 
					 * seconds, it is repeated for 5 times. Since this is the third wave, after the
 | 
				
			||||||
 | 
					 * repetitions the LED returns to alternating between wave 0 and wave 1, this
 | 
				
			||||||
 | 
					 * wave is discarded.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Set multiple waves at once:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader set 0 0 15 10 1 0 1 25 10 1 0 2 36 20 5
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This will set all of the above waves at once. Thus, the first LED will first
 | 
				
			||||||
 | 
					 * fade the sinus-wave five times, then start alternating between the two
 | 
				
			||||||
 | 
					 * brightnesses in one-second-rhythm.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Clear the first LED:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader clear 0
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This will clear all three waves on the first LED.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Reset the device:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader reset
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * All LEDs will flash once, to indicate that the device is reset and the LEDs
 | 
				
			||||||
 | 
					 * are working.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Show a waveform on the screen:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader show 36
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This will lead to an output like the following:
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * wave 36 - length 64
 | 
				
			||||||
 | 
					 * 31:                              *****
 | 
				
			||||||
 | 
					 * 30:                            *********
 | 
				
			||||||
 | 
					 * 29:                           ***********
 | 
				
			||||||
 | 
					 * 28:                         ***************
 | 
				
			||||||
 | 
					 * 27:                        *****************
 | 
				
			||||||
 | 
					 * 26:                       *******************
 | 
				
			||||||
 | 
					 * 25:                       *******************
 | 
				
			||||||
 | 
					 * 24:                      *********************
 | 
				
			||||||
 | 
					 * 23:                     ***********************
 | 
				
			||||||
 | 
					 * 22:                    *************************
 | 
				
			||||||
 | 
					 * 21:                    *************************
 | 
				
			||||||
 | 
					 * 20:                   ***************************
 | 
				
			||||||
 | 
					 * 19:                  *****************************
 | 
				
			||||||
 | 
					 * 18:                  *****************************
 | 
				
			||||||
 | 
					 * 17:                 *******************************
 | 
				
			||||||
 | 
					 * 16:                *********************************
 | 
				
			||||||
 | 
					 * 15:               ***********************************
 | 
				
			||||||
 | 
					 * 14:               ***********************************
 | 
				
			||||||
 | 
					 * 13:              *************************************
 | 
				
			||||||
 | 
					 * 12:             ***************************************
 | 
				
			||||||
 | 
					 * 11:             ***************************************
 | 
				
			||||||
 | 
					 * 10:            *****************************************
 | 
				
			||||||
 | 
					 *  9:           *******************************************
 | 
				
			||||||
 | 
					 *  8:          *********************************************
 | 
				
			||||||
 | 
					 *  7:          *********************************************
 | 
				
			||||||
 | 
					 *  6:         ***********************************************
 | 
				
			||||||
 | 
					 *  5:        *************************************************
 | 
				
			||||||
 | 
					 *  4:      *****************************************************
 | 
				
			||||||
 | 
					 *  3:     *******************************************************
 | 
				
			||||||
 | 
					 *  2:   ***********************************************************
 | 
				
			||||||
 | 
					 *  1: ****************************************************************
 | 
				
			||||||
 | 
					 *     ================================================================
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * Keep in mind that the width of the displayed wave corresponds to the length
 | 
				
			||||||
 | 
					 * of the waveform. If you display a very simple one like the constant
 | 
				
			||||||
 | 
					 * brightness levels (0-31), the length is 1. Therefore only one column is
 | 
				
			||||||
 | 
					 * displayed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <b>Test the device:</b>
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * usb-led-fader test
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 * This function sends many random numbers to the device. The device returns
 | 
				
			||||||
 | 
					 * the packages, and the client looks for differences in the sent and the
 | 
				
			||||||
 | 
					 * received numbers.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_drawbacks Drawbacks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * As mentioned above, controlling the PWM for several LEDs is a lot of work
 | 
				
			||||||
 | 
					 * for one small microcontroller. Speaking the USB protocol is so, either. Both
 | 
				
			||||||
 | 
					 * combined result in a lot of load on the device, so the communication with
 | 
				
			||||||
 | 
					 * the device is not 100% reliable. More than 99% though, at least in our
 | 
				
			||||||
 | 
					 * tests.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * <b>SO BE WARNED:</b> You should not use this device to control the state of
 | 
				
			||||||
 | 
					 * your nuclear reactor. If you intend to use it in that way despite of this
 | 
				
			||||||
 | 
					 * warning, please let me know... ;-)
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * \section sec_files Files in the distribution
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * - \e Readme.txt: The file you are currently reading.
 | 
				
			||||||
 | 
					 * - \e firmware: Source code of the controller firmware.
 | 
				
			||||||
 | 
					 * - \e firmware/usbdrv: USB driver -- See Readme.txt in this directory for
 | 
				
			||||||
 | 
					 *   info
 | 
				
			||||||
 | 
					 * - \e commandline: Source code of the host software (needs libusb).
 | 
				
			||||||
 | 
					 * - \e common: Files needed by the firmware and the commandline-client.
 | 
				
			||||||
 | 
					 * - \e circuit: Circuit diagrams in PDF and EAGLE 4 format. A free version of
 | 
				
			||||||
 | 
					 *   EAGLE is available for Linux, Mac OS X and Windows from
 | 
				
			||||||
 | 
					 *   http://www.cadsoft.de/.
 | 
				
			||||||
 | 
					 * - \e License.txt: Public license for all contents of this project, except
 | 
				
			||||||
 | 
					 *   for the USB driver. Look in firmware/usbdrv/License.txt for further info.
 | 
				
			||||||
 | 
					 * - \e Changelog.txt: Logfile documenting changes in soft-, firm- and
 | 
				
			||||||
 | 
					 *   hardware.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * \section sec_thanks Thanks!
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * I'd like to thank <b>Objective Development</b> for the possibility to use
 | 
				
			||||||
 | 
					 * their driver for my project. In fact, this project wouldn't exist without
 | 
				
			||||||
 | 
					 * the driver.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * And I'd like to give special credits to <b>Thomas Stegemann</b>. He wrote
 | 
				
			||||||
 | 
					 * the PWM-stuff, and I guess it would have been nearly to impossible to me to
 | 
				
			||||||
 | 
					 * write the rest of the project without his help since C isn't my natural
 | 
				
			||||||
 | 
					 * language.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * \section sec_license About the license
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Our work - all contents except for the USB driver - are licensed under the
 | 
				
			||||||
 | 
					 * GNU General Public License (GPL). A copy of the GPL is included in
 | 
				
			||||||
 | 
					 * License.txt. The driver itself is licensed under a special license by
 | 
				
			||||||
 | 
					 * Objective Development. See firmware/usbdrv/License.txt for further info.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * <b>(c) 2006 by Ronald Schaten - http://www.schatenseite.de</b>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* return codes for USB-communication */
 | 
				
			||||||
 | 
					#define msgOK 0     /**< Return code for OK. */
 | 
				
			||||||
 | 
					#define msgErr 1    /**< Return code for Error. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* These are the vendor specific SETUP commands implemented by our USB device */
 | 
				
			||||||
 | 
					#define CMD_ECHO  0 /**< Command to echo the sent data */
 | 
				
			||||||
 | 
					#define CMD_GET   1 /**< Command to fetch values */
 | 
				
			||||||
 | 
					#define CMD_SET   2 /**< Command to send values */
 | 
				
			||||||
 | 
					#define CMD_CLEAR 3 /**< Command to switch off a certain LED */
 | 
				
			||||||
 | 
					#define CMD_RESET 4 /**< Command to reset the whole device */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Description of one waveform. */
 | 
				
			||||||
 | 
					typedef struct S_fade_Waveform {
 | 
				
			||||||
 | 
					    uint8_t waveformId; /**< ID of this waveform. */
 | 
				
			||||||
 | 
					    uint8_t waveformLength; /**< Length of this waveform. */
 | 
				
			||||||
 | 
					    uint8_t waveformRepetition; /**< How often is this waveform to be repeated? */
 | 
				
			||||||
 | 
					    uint8_t waveformDuration; /**< Duration for one cycle of this waveform, stored for status-output. */
 | 
				
			||||||
 | 
					    uint32_t waveformUpdateTime; /**< Time between two waveform-samples in calls of timerInterrupt(), calculated from waveformDuration. */
 | 
				
			||||||
 | 
					} fade_Waveform;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** The state of one LED. */
 | 
				
			||||||
 | 
					typedef struct S_fade_LedState {
 | 
				
			||||||
 | 
					    fade_Waveform wave[3]; /**< Three waveforms: base-function1, base-function2 and override-function. */
 | 
				
			||||||
 | 
					    uint8_t waveCurrentId; /**< Which of the three waveforms is currently displayed? */
 | 
				
			||||||
 | 
					    uint8_t waveCurrentValue; /**< The current brightness. */
 | 
				
			||||||
 | 
					    uint8_t waveCurrentPosition; /**< Our position in the current waveform. */
 | 
				
			||||||
 | 
					    uint8_t waveCurrentRepetition; /**< We are in the n-th repetition. */
 | 
				
			||||||
 | 
					    int32_t waveNextUpdate; /**< Number of cycles till next update. */
 | 
				
			||||||
 | 
					} fade_LedState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Contains the state of all four LEDs. */
 | 
				
			||||||
 | 
					typedef struct S_fade_GlobalData {
 | 
				
			||||||
 | 
					    fade_LedState led[4];     /**< Data for four LEDs. */
 | 
				
			||||||
 | 
					} fade_GlobalData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t fade_calculateWaveform(uint8_t waveformId, uint8_t waveformPosition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate a waveform. Returns either the length of a given waveform or the
 | 
				
			||||||
 | 
					 * output-level at a certain position in the wave.
 | 
				
			||||||
 | 
					 * \param waveformId ID of the waveform in question.
 | 
				
			||||||
 | 
					 * \param waveformPosition 0 or position in the given waveform.
 | 
				
			||||||
 | 
					 * \return If the waveformPosition is 0, the number of steps in this waveform is returned. Otherwise the resulting output-level, an integer between 0 and 31.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uint8_t fade_calculateWaveform(uint8_t waveformId, uint8_t waveformPosition) {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * values for sinus-wave, amplitude 31, 64 steps:
 | 
				
			||||||
 | 
					     * awk 'BEGIN{ pi=3.1415927; for(i=1; i<=64; i++) { printf("%.0f, ", sin(i*pi/32)*31) } printf("\n"); }'
 | 
				
			||||||
 | 
					     *  3,  6,  9, 12, 15, 17, 20, 22, 24, 26, 27, 29, 30, 30, 31, 31, 31, 30,
 | 
				
			||||||
 | 
					     *  30, 29, 27, 26, 24, 22, 20, 17, 15, 12,  9,  6,  3, -0, -3, -6, -9,
 | 
				
			||||||
 | 
					     *  -12, -15, -17, -20, -22, -24, -26, -27, -29, -30, -30, -31, -31, -31,
 | 
				
			||||||
 | 
					     *  -30, -30, -29, -27, -26, -24, -22, -20, -17, -15, -12, -9, -6, -3,  0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* sinus-wave:
 | 
				
			||||||
 | 
					     * awk 'BEGIN{ pi=3.1415927; for(i=1; i<=64; i++) { printf("%.0f, ", sin((i+48)*pi/32)*15+16) } printf("\n"); }'
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    uint8_t sinus[] = { 1, 1, 2, 2, 3, 4, 4, 5, 6, 8, 9, 10, 12, 13, 15, 16,
 | 
				
			||||||
 | 
					        17, 19, 20, 22, 23, 24, 26, 27, 28, 28, 29, 30, 30, 31, 31, 31, 31, 31,
 | 
				
			||||||
 | 
					        30, 30, 29, 28, 28, 27, 26, 24, 23, 22, 20, 19, 17, 16, 15, 13, 12, 10,
 | 
				
			||||||
 | 
					        9, 8, 6, 5, 4, 4, 3, 2, 2, 1, 1, 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * another nice wave, wider than the original sinus:
 | 
				
			||||||
 | 
					     * awk 'BEGIN{ pi=3.1415927; for(i=1; i<=32; i++) { printf("%.0f, ", sqrt(sin(i*pi/32)*31+.00001)*sqrt(32)) } printf("\n"); }'
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    uint8_t widecurve[] = { 10, 14, 17, 19, 22, 23, 25, 26, 28, 29, 30, 30, 31,
 | 
				
			||||||
 | 
					        31, 31, 31, 31, 31, 31, 30, 30, 29, 28, 26, 25, 23, 22, 19, 17, 14, 10,
 | 
				
			||||||
 | 
					        0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (waveformId <= 31) {
 | 
				
			||||||
 | 
					        /* No fading, just a constant level */
 | 
				
			||||||
 | 
					        if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					            return 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return waveformId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        switch (waveformId) {
 | 
				
			||||||
 | 
					        case 32:               /* blink */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 2;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if (waveformPosition == 1) {
 | 
				
			||||||
 | 
					                    return 31;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        case 33:               /* triangular */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 62;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if (waveformPosition <= 32) {
 | 
				
			||||||
 | 
					                    return waveformPosition - 1;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return 63 - waveformPosition;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        case 34:               /* sawtooth rising */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 32;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return waveformPosition - 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        case 35:               /* sawtooth falling */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 32;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return 31 - (waveformPosition - 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        case 36:               /* sinus */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 64;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return sinus[waveformPosition - 1];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        case 37:               /* wide curve */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 32;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return widecurve[waveformPosition - 1];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        case 38:               /* wide curve - inverted */
 | 
				
			||||||
 | 
					            if (waveformPosition == 0) {
 | 
				
			||||||
 | 
					                return 32;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return 31 - widecurve[(waveformPosition + 15) % 32];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										48
									
								
								firmware/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								firmware/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					# $Id: Makefile,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AVRDUDE = avrdude -p atmega8 -P /dev/parport0 -c stk200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMPILE = avr-gcc -Wall -Os -Iusbdrv -I../common -I. -mmcu=atmega8 #-DDEBUG_LEVEL=2
 | 
				
			||||||
 | 
					# NEVER compile the final product with debugging! Any debug output will
 | 
				
			||||||
 | 
					# distort timing so that the specs can't be met.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o pwm_timer.o pwm_channels.o message_queue.o
 | 
				
			||||||
 | 
					# Note that we link usbdrv.o first! This is required for correct alignment of
 | 
				
			||||||
 | 
					# driver-internal global variables!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# symbolic targets:
 | 
				
			||||||
 | 
					all:	main.hex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.c.o:
 | 
				
			||||||
 | 
						$(COMPILE) -c $< -o $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.S.o:
 | 
				
			||||||
 | 
						$(COMPILE) -x assembler-with-cpp -c $< -o $@
 | 
				
			||||||
 | 
					# "-x assembler-with-cpp" should not be necessary since this is the default
 | 
				
			||||||
 | 
					# file type for the .S (with capital S) extension. However, upper case
 | 
				
			||||||
 | 
					# characters are not always preserved on Windows. To ensure WinAVR
 | 
				
			||||||
 | 
					# compatibility define the file type manually.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.c.s:
 | 
				
			||||||
 | 
						$(COMPILE) -S $< -o $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					program:	all
 | 
				
			||||||
 | 
						$(AVRDUDE) -E noreset,vcc -U flash:w:main.hex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# file targets:
 | 
				
			||||||
 | 
					main.bin:	$(OBJECTS)
 | 
				
			||||||
 | 
						$(COMPILE) -o main.bin $(OBJECTS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main.hex:	main.bin
 | 
				
			||||||
 | 
						rm -f main.hex main.eep.hex
 | 
				
			||||||
 | 
						avr-objcopy -j .text -j .data -O ihex main.bin main.hex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					disasm:	main.bin
 | 
				
			||||||
 | 
						avr-objdump -d main.bin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cpp:
 | 
				
			||||||
 | 
						$(COMPILE) -E main.c
 | 
				
			||||||
							
								
								
									
										34
									
								
								firmware/boolean.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								firmware/boolean.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#ifndef boolean_h
 | 
				
			||||||
 | 
					#define boolean_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file boolean.h
 | 
				
			||||||
 | 
					 * \brief Provides boolean variables in C.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: boolean.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Possible boolean values */
 | 
				
			||||||
 | 
					typedef enum E_Boolean {
 | 
				
			||||||
 | 
					    False = 0, /**< logical false */
 | 
				
			||||||
 | 
					    True = 1 /**< logical true */
 | 
				
			||||||
 | 
					} Boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Boolean function. Returns true or false, depending on the given condition.
 | 
				
			||||||
 | 
					 * \param condition The condition to evaluate, must be integer.
 | 
				
			||||||
 | 
					 * \return True or false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline Boolean
 | 
				
			||||||
 | 
					boolean (int condition)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (condition) {
 | 
				
			||||||
 | 
					        return True;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return False;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										26
									
								
								firmware/config_message_queue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								firmware/config_message_queue.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#ifndef config_message_queue_h
 | 
				
			||||||
 | 
					#define config_message_queue_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file config_message_queue.h
 | 
				
			||||||
 | 
					 * \brief Configures the message-queue.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: config_message_queue.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - define the size of the messageQueue(messageQueue_Size) and the type of the
 | 
				
			||||||
 | 
					 *   messageQueue_QueuedMessage
 | 
				
			||||||
 | 
					 * - check that messageQueue_SizeType can hold 0..messageQueue_Size+1
 | 
				
			||||||
 | 
					 * - the messageQueue buffers up to messageQueue_Size messages of the type
 | 
				
			||||||
 | 
					 *   messageQueue_QueuedMessage
 | 
				
			||||||
 | 
					 * - currently the messageQueue is used by pwm_Channels and pwm_Timer with the
 | 
				
			||||||
 | 
					 *   pwm_Channels_Message
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pwm_timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef pwm_Channels_Message messageQueue_QueuedMessage;
 | 
				
			||||||
 | 
					enum { messageQueue_Size = 3 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										23
									
								
								firmware/config_message_queue_impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								firmware/config_message_queue_impl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					#ifndef config_message_queue_impl_h
 | 
				
			||||||
 | 
					#define config_message_queue_impl_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file config_message_queue_impl.h
 | 
				
			||||||
 | 
					 * \brief Configures the implementation of the message-queue.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: config_message_queue_impl.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - define the SizeType for the messageQueue
 | 
				
			||||||
 | 
					 * - the messageQueue_SizeType must hold 0..messageQueue_Size + 1, see
 | 
				
			||||||
 | 
					 *   config_message_queue.h
 | 
				
			||||||
 | 
					 * - the messageQueue_SizeType must be read/written by the processor in an
 | 
				
			||||||
 | 
					 *   atomic instruction
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef uint8_t messageQueue_SizeType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										27
									
								
								firmware/config_pwm_timer_impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								firmware/config_pwm_timer_impl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#ifndef config_pwm_timer_impl_h
 | 
				
			||||||
 | 
					#define config_pwm_timer_impl_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file config_pwm_timer_impl.h
 | 
				
			||||||
 | 
					 * \brief Configures the implementation of the PWM-timer.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: config_pwm_timer_impl.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - pwm_Timer_Cycles_Max defines the number of (prescaled) processor cycles
 | 
				
			||||||
 | 
					 *   for a full pwm_TimerCycle
 | 
				
			||||||
 | 
					 * - pwm_Timer_Cycles_ReadMin defines the number of (prescaled) processor
 | 
				
			||||||
 | 
					 *   cycles the reading from the message queue may last
 | 
				
			||||||
 | 
					 * - pwm_Timer_Cycles_SleepMax defines the minimum number of (prescaled)
 | 
				
			||||||
 | 
					 *   processor cycles for which the timer is used. for less cycles the
 | 
				
			||||||
 | 
					 *   pwm_Timer waits active
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pwm_channels.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum { pwm_Timer_Cycles_Max = pwm_Channels_Brightness_Max * pwm_Channels_Brightness_Max };
 | 
				
			||||||
 | 
					enum { pwm_Timer_Cycles_ReadMin = 2 };
 | 
				
			||||||
 | 
					enum { pwm_Timer_Cycles_SleepMax = 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										278
									
								
								firmware/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								firmware/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,278 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file main.c
 | 
				
			||||||
 | 
					 * \brief Firmware for the USB-LED-Fader.
 | 
				
			||||||
 | 
					 * \author Ronald Schaten & Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: main.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					#include <avr/interrupt.h>
 | 
				
			||||||
 | 
					#include <avr/pgmspace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "usbdrv.h"
 | 
				
			||||||
 | 
					#include "oddebug.h"
 | 
				
			||||||
 | 
					#include "pwm_channels.h"
 | 
				
			||||||
 | 
					#include "usbledfader.h"
 | 
				
			||||||
 | 
					#include "channels.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Global variable, contains the state of all four LEDs. */
 | 
				
			||||||
 | 
					static fade_GlobalData fade_globalData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Global variable, contains the rest-amount of data to send to the host. */
 | 
				
			||||||
 | 
					static uint8_t usbRead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler for the timer-interrupt. Determines the state of the four LEDs and
 | 
				
			||||||
 | 
					 * calls pwm_Channels_show() if something is to be changed.  This function
 | 
				
			||||||
 | 
					 * contains the logic by which the waveforms are assigned to the LEDs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void timerInterrupt(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t i = 0, changed = 0;
 | 
				
			||||||
 | 
					    for (i = 0; i < CHANNELS; i++) {
 | 
				
			||||||
 | 
					        fade_LedState *pLed = &(fade_globalData.led[i]);        /* fetch current LED */
 | 
				
			||||||
 | 
					        pLed->waveNextUpdate--;
 | 
				
			||||||
 | 
					        if (pLed->waveNextUpdate <= 0) {        /* time to update */
 | 
				
			||||||
 | 
					            fade_Waveform *pWave = &(pLed->wave[pLed->waveCurrentId]);  /* fetch currently active wave */
 | 
				
			||||||
 | 
					            pLed->waveCurrentPosition++;        /* go to next position */
 | 
				
			||||||
 | 
					            if (pLed->waveCurrentPosition > pWave->waveformLength) {
 | 
				
			||||||
 | 
					                pLed->waveCurrentPosition = 1;  /* restart wave */
 | 
				
			||||||
 | 
					                if (pWave->waveformRepetition == 0) {
 | 
				
			||||||
 | 
					                    /* repeat this waveform forever */
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    /* next repetition */
 | 
				
			||||||
 | 
					                    pLed->waveCurrentRepetition++;
 | 
				
			||||||
 | 
					                    if (pLed->waveCurrentRepetition >= pWave->waveformRepetition) { /* enough of this wave */
 | 
				
			||||||
 | 
					                        pLed->waveCurrentRepetition = 0;    /* reset repetition counter */
 | 
				
			||||||
 | 
					                        switch (pLed->waveCurrentId) {     /* activate next wave */
 | 
				
			||||||
 | 
					                            case 0:
 | 
				
			||||||
 | 
					                                if (pLed->wave[1].waveformDuration > 0) { /* only activate if a wave is set */
 | 
				
			||||||
 | 
					                                    pLed->waveCurrentId = 1;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            case 1:
 | 
				
			||||||
 | 
					                                if (pLed->wave[0].waveformDuration > 0) { /* only activate if a wave is set */
 | 
				
			||||||
 | 
					                                    pLed->waveCurrentId = 0;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            case 2:
 | 
				
			||||||
 | 
					                                /* wave 2 is only to be repeated the given times,
 | 
				
			||||||
 | 
					                                 * reset and continue with wave 0 */
 | 
				
			||||||
 | 
					                                pWave->waveformId = 0;
 | 
				
			||||||
 | 
					                                pWave->waveformLength = fade_calculateWaveform(pWave->waveformId, 0);
 | 
				
			||||||
 | 
					                                pWave->waveformRepetition = 1;
 | 
				
			||||||
 | 
					                                pWave->waveformDuration = 0;
 | 
				
			||||||
 | 
					                                pWave->waveformUpdateTime = 1;
 | 
				
			||||||
 | 
					                                pLed->waveCurrentId = 0;
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            uint8_t newValue = fade_calculateWaveform(pLed->wave[pLed->waveCurrentId].waveformId, pLed->waveCurrentPosition); /* fetch new value */
 | 
				
			||||||
 | 
					            if (newValue != pLed->waveCurrentValue) {   /* only update if the value has changed */
 | 
				
			||||||
 | 
					                pLed->waveCurrentValue = newValue;
 | 
				
			||||||
 | 
					                changed = 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            pLed->waveNextUpdate = pLed->wave[pLed->waveCurrentId].waveformUpdateTime; /* next update according to the wave's settings */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (changed) {              /* any value has changed, update all LEDs */
 | 
				
			||||||
 | 
					        pwm_Channels channels;
 | 
				
			||||||
 | 
					        for (i = 0; i < CHANNELS; i++) {
 | 
				
			||||||
 | 
					            channels.channel[i] = fade_globalData.led[i].waveCurrentValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pwm_Channels_show(channels);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Start displaying a certain waveform on a single LED.
 | 
				
			||||||
 | 
					 * \param ledId ID of the LED that is changed.
 | 
				
			||||||
 | 
					 * \param waveId ID of the wave that to be set: 0 and 1 are the base waves, 2 is the override wave.
 | 
				
			||||||
 | 
					 * \param waveformId ID of the Waveform that is to be assigned to the LED.
 | 
				
			||||||
 | 
					 * \param periodDuration How long should this wave stay on display? Time in seconds/10.
 | 
				
			||||||
 | 
					 * \param repetitionCount How many times should this wave be repeated while it is on display?
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void fade_startWaveform(uint8_t ledId, uint8_t waveId, uint8_t waveformId, uint8_t periodDuration, uint8_t repetitionCount) {
 | 
				
			||||||
 | 
					    if ((ledId < CHANNELS) && (waveId < 3)) {
 | 
				
			||||||
 | 
					        fade_LedState *pLed = &(fade_globalData.led[ledId]);
 | 
				
			||||||
 | 
					        fade_Waveform *pWave = &(pLed->wave[waveId]);
 | 
				
			||||||
 | 
					        pLed->waveCurrentId = waveId;
 | 
				
			||||||
 | 
					        pLed->waveCurrentPosition = 0;
 | 
				
			||||||
 | 
					        pLed->waveCurrentRepetition = 0;
 | 
				
			||||||
 | 
					        pLed->waveNextUpdate = 0;
 | 
				
			||||||
 | 
					        if (periodDuration > 0) {
 | 
				
			||||||
 | 
					            pWave->waveformId = waveformId;
 | 
				
			||||||
 | 
					            pWave->waveformLength = fade_calculateWaveform(waveformId, 0);
 | 
				
			||||||
 | 
					            pWave->waveformRepetition = repetitionCount;
 | 
				
			||||||
 | 
					            pWave->waveformDuration = periodDuration;
 | 
				
			||||||
 | 
					            /* waveformUpdateTime in calls of timerInterrupt().
 | 
				
			||||||
 | 
					             * periodDuration in seconds/10.
 | 
				
			||||||
 | 
					             * 12000000 cycles per second
 | 
				
			||||||
 | 
					             * 64 cycles per timer/counter (prescaler)
 | 
				
			||||||
 | 
					             * 256 timer/counter per interrupt-call
 | 
				
			||||||
 | 
					             * -> (12000000 / (256 * 64)) = 732 calls per second */
 | 
				
			||||||
 | 
					            pWave->waveformUpdateTime = ((uint32_t)periodDuration * 12000000 / 256 / 64 / 10 / pWave->waveformLength );
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            /* periodDuration = 0, reset the wave */
 | 
				
			||||||
 | 
					            pWave->waveformId = 0;
 | 
				
			||||||
 | 
					            pWave->waveformLength = fade_calculateWaveform(pWave->waveformId, 0);
 | 
				
			||||||
 | 
					            pWave->waveformRepetition = 1;
 | 
				
			||||||
 | 
					            pWave->waveformDuration = 0;
 | 
				
			||||||
 | 
					            pWave->waveformUpdateTime = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Fills fade_globalData. The state of all LEDs is initialized to off. One
 | 
				
			||||||
 | 
					 * signal is displayed on all LEDs to ensure they're working.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void fade_globalData_init(void) {
 | 
				
			||||||
 | 
					    int i = 0, j = 0;
 | 
				
			||||||
 | 
					    for (i = 0; i < CHANNELS; i++) {
 | 
				
			||||||
 | 
					        fade_globalData.led[i].waveCurrentId = 0;
 | 
				
			||||||
 | 
					        fade_globalData.led[i].waveCurrentPosition = 0;
 | 
				
			||||||
 | 
					        fade_globalData.led[i].waveCurrentRepetition = 0;
 | 
				
			||||||
 | 
					        fade_globalData.led[i].waveNextUpdate = 0;
 | 
				
			||||||
 | 
					        for (j = 0; j < 3; j++) {
 | 
				
			||||||
 | 
					            fade_globalData.led[i].wave[j].waveformId = 0;
 | 
				
			||||||
 | 
					            fade_globalData.led[i].wave[j].waveformLength =
 | 
				
			||||||
 | 
					                fade_calculateWaveform(fade_globalData.led[i].wave[j].
 | 
				
			||||||
 | 
					                                       waveformId, 0);
 | 
				
			||||||
 | 
					            fade_globalData.led[i].wave[j].waveformRepetition = 1;
 | 
				
			||||||
 | 
					            fade_globalData.led[i].wave[j].waveformDuration = 0;
 | 
				
			||||||
 | 
					            fade_globalData.led[i].wave[j].waveformUpdateTime = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* show that we are ready */
 | 
				
			||||||
 | 
					    for (i = 0; i < CHANNELS; i++) {
 | 
				
			||||||
 | 
					        fade_startWaveform(i, 2, 36, 10, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * USB-Data-Handler (device -> host). Handles data that is to be sent to the
 | 
				
			||||||
 | 
					 * host via USB-Interface. In our case the data contains the current settings
 | 
				
			||||||
 | 
					 * for the LEDs. This function is called until the returned length is shorter
 | 
				
			||||||
 | 
					 * than the buffer (typically 8 bytes).
 | 
				
			||||||
 | 
					 * \param data Buffer for the data.
 | 
				
			||||||
 | 
					 * \param len Length of the buffer.
 | 
				
			||||||
 | 
					 * \return Length of the returned buffer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uchar usbFunctionRead(uchar *data, uchar len) {
 | 
				
			||||||
 | 
					    uint8_t i = 0;
 | 
				
			||||||
 | 
					    uint8_t *p_fade_globalData = (uint8_t*)&fade_globalData;
 | 
				
			||||||
 | 
					    while ((i < len) && (usbRead < sizeof(fade_GlobalData))) {
 | 
				
			||||||
 | 
					        data[i] = p_fade_globalData[usbRead];
 | 
				
			||||||
 | 
					        usbRead++;
 | 
				
			||||||
 | 
					        i++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return i;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * USB-Data-Handler (host -> device). Handles data that is received from the
 | 
				
			||||||
 | 
					 * USB-Interface. In our case the data contains settings for the LEDs.
 | 
				
			||||||
 | 
					 * \param data The received data, up to 8 bytes.
 | 
				
			||||||
 | 
					 * \param len Length of the received data.
 | 
				
			||||||
 | 
					 * \return 1 if we have received the entire payload successfully, 0 if we expect more data. We don't, so we always return 1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uchar usbFunctionWrite(uchar *data, uchar len) {
 | 
				
			||||||
 | 
					    /* parameters:
 | 
				
			||||||
 | 
					     * data[0]: command (0: echo, 1: read status, 2: set status, 3: clear)
 | 
				
			||||||
 | 
					     * data[1]: ledId
 | 
				
			||||||
 | 
					     * data[2]: waveId
 | 
				
			||||||
 | 
					     * data[3]: waveformId
 | 
				
			||||||
 | 
					     * data[4]: periodDuration
 | 
				
			||||||
 | 
					     * data[5]: repetitionCount
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fade_startWaveform(data[1], data[2], data[3], data[4], data[5]);
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * USB-Setup-Handler. Handles setup-calls that are received from the
 | 
				
			||||||
 | 
					 * USB-Interface.
 | 
				
			||||||
 | 
					 * \param data Eight bytes of data.
 | 
				
			||||||
 | 
					 * \return The number of returned bytes (in replyBuffer[]).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uchar usbFunctionSetup(uchar data[8]) {
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    static uchar replyBuffer[8];
 | 
				
			||||||
 | 
					    uchar replyLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    replyBuffer[0] = msgOK;
 | 
				
			||||||
 | 
					    switch (data[1]) {
 | 
				
			||||||
 | 
					    case CMD_ECHO:                    /* echo */
 | 
				
			||||||
 | 
					        replyBuffer[0] = data[2];
 | 
				
			||||||
 | 
					        replyBuffer[1] = data[3];
 | 
				
			||||||
 | 
					        replyLength = 2;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case CMD_GET:                    /* read status */
 | 
				
			||||||
 | 
					        usbRead = 0;
 | 
				
			||||||
 | 
					        replyLength = 0xff; /* special value, indicates that usbFunctionRead() has to be called */
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case CMD_SET:                    /* set status */
 | 
				
			||||||
 | 
					        replyLength = 0xff; /* special value, indicates that usbFunctionWrite() has to be called */
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case CMD_CLEAR:                  /* clear one LED */
 | 
				
			||||||
 | 
					        for (i = 0; i <= 2; i++) {
 | 
				
			||||||
 | 
					            /* clear all three waves on this LED */
 | 
				
			||||||
 | 
					            fade_startWaveform(data[2], i, 0, 0, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        replyLength = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case CMD_RESET:                  /* reset the device */
 | 
				
			||||||
 | 
					        fade_globalData_init();
 | 
				
			||||||
 | 
					        replyLength = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:                         /* WTF? */
 | 
				
			||||||
 | 
					        replyBuffer[0] = msgErr;
 | 
				
			||||||
 | 
					        replyLength = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usbMsgPtr = replyBuffer;
 | 
				
			||||||
 | 
					    return replyLength;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Main-function. Initializes the hardware and starts the main loop of the
 | 
				
			||||||
 | 
					 * application.
 | 
				
			||||||
 | 
					 * \return An integer. Whatever... :-)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int main(void) {
 | 
				
			||||||
 | 
					    uchar i, j;
 | 
				
			||||||
 | 
					    odDebugInit();
 | 
				
			||||||
 | 
					    DDRB = ~0;                  /* output SE0 for USB reset */
 | 
				
			||||||
 | 
					    PORTB = 0x00;               /* no pullups on USB pins */
 | 
				
			||||||
 | 
					    DDRC = 0xff;                /* all outputs */
 | 
				
			||||||
 | 
					    PORTC = 0x00;
 | 
				
			||||||
 | 
					    DDRD = 0x00;                /* all inputs */
 | 
				
			||||||
 | 
					    PORTD = 0x00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    j = 0;
 | 
				
			||||||
 | 
					    while (--j) {               /* USB Reset by device only required on Watchdog Reset */
 | 
				
			||||||
 | 
					        i = 0;
 | 
				
			||||||
 | 
					        while (--i);            /* delay >10ms for USB reset */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    DDRB = ~USBMASK;            /* all outputs except USB data */
 | 
				
			||||||
 | 
					    TCCR0 = 3;                  /* set prescaler to 1/64 */
 | 
				
			||||||
 | 
					    usbInit();
 | 
				
			||||||
 | 
					    sei();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pwm_Channels_init();
 | 
				
			||||||
 | 
					    fade_globalData_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (1) {                 /* main event loop */
 | 
				
			||||||
 | 
					        usbPoll();
 | 
				
			||||||
 | 
					        if (TIFR & (1 << TOV0)) {
 | 
				
			||||||
 | 
					            TIFR |= 1 << TOV0;  /* clear pending flag */
 | 
				
			||||||
 | 
					            timerInterrupt();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										95
									
								
								firmware/message_queue.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								firmware/message_queue.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file message_queue.c
 | 
				
			||||||
 | 
					 * \brief A message queue used to exchange messages between two concurrent threads.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: message_queue.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include "message_queue.h"
 | 
				
			||||||
 | 
					#include "config_message_queue_impl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Structure of the global data of the queue */
 | 
				
			||||||
 | 
					typedef struct S_messageQueue_GlobalData {
 | 
				
			||||||
 | 
					    messageQueue_QueuedMessage queue[messageQueue_Size]; /**< the queue itself */
 | 
				
			||||||
 | 
					    messageQueue_SizeType begin; /**< the current start of the queue */
 | 
				
			||||||
 | 
					    messageQueue_SizeType end; /**< the current end of the queue */
 | 
				
			||||||
 | 
					} messageQueue_GlobalData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Global data of the queue */
 | 
				
			||||||
 | 
					static volatile messageQueue_GlobalData m_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the next entry fron the queue.
 | 
				
			||||||
 | 
					 * \param value Number of the current entry.
 | 
				
			||||||
 | 
					 * \return 0 if the value is larger than the queue, otherwise the next entry.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline messageQueue_SizeType messageQueue_next(messageQueue_SizeType value) {
 | 
				
			||||||
 | 
					    value++;
 | 
				
			||||||
 | 
					    if(value >= messageQueue_Size) {
 | 
				
			||||||
 | 
					        value= 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize the queue.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void messageQueue_init(void) {
 | 
				
			||||||
 | 
					    m_data.begin= 0;
 | 
				
			||||||
 | 
					    m_data.end= 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clean up the queue. Currently this does nothing.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void messageQueue_cleanup(void)
 | 
				
			||||||
 | 
					{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Test if the queue is empty.
 | 
				
			||||||
 | 
					 * \return True if it is empty, otherwise false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Boolean messageQueue_isEmpty(void) {
 | 
				
			||||||
 | 
					    return boolean(m_data.begin == m_data.end);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Test if the queue is full. If it is full, new entries will overwrite the
 | 
				
			||||||
 | 
					 * first entries.
 | 
				
			||||||
 | 
					 * \return True if it is full, otherwise false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Boolean messageQueue_isFull(void) {
 | 
				
			||||||
 | 
					    return boolean(messageQueue_next(m_data.end) == m_data.begin);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Read a message from the queue.
 | 
				
			||||||
 | 
					 * \param pMessage Pointer to a message variable that should be set to the
 | 
				
			||||||
 | 
					 * message.
 | 
				
			||||||
 | 
					 * \return True if an entry could be read, otherwise false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Boolean messageQueue_read(messageQueue_QueuedMessage* pMessage) {
 | 
				
			||||||
 | 
					    Boolean success= !messageQueue_isEmpty();
 | 
				
			||||||
 | 
					    if(success) {
 | 
				
			||||||
 | 
					        *pMessage= m_data.queue[m_data.begin];
 | 
				
			||||||
 | 
					        m_data.begin= messageQueue_next(m_data.begin);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return success;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Write a message to the queue.
 | 
				
			||||||
 | 
					 * \param message The message to append.
 | 
				
			||||||
 | 
					 * \return True if the message could be appended, otherwise false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Boolean messageQueue_write(messageQueue_QueuedMessage message) {
 | 
				
			||||||
 | 
					    Boolean success= !messageQueue_isFull();
 | 
				
			||||||
 | 
					    if(success) {
 | 
				
			||||||
 | 
					        m_data.queue[m_data.end]= message;
 | 
				
			||||||
 | 
					        m_data.end= messageQueue_next(m_data.end);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return success;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										37
									
								
								firmware/message_queue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								firmware/message_queue.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					#ifndef message_queue_h
 | 
				
			||||||
 | 
					#define message_queue_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file message_queue.h
 | 
				
			||||||
 | 
					 * \brief A message queue used to exchange messages between two concurrent
 | 
				
			||||||
 | 
					 * threads.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: message_queue.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - exchange messages between two concurrent threads (e.g.: main thread and
 | 
				
			||||||
 | 
					 *   interrupt calls)
 | 
				
			||||||
 | 
					 * - before using any other function of the messageQueue, init must be called
 | 
				
			||||||
 | 
					 * - one thread must be data source (use isFull and write)
 | 
				
			||||||
 | 
					 * - the other thread must be the data sink (use isEmpty and read)
 | 
				
			||||||
 | 
					 * - two concurrent threads must not use both the write functions and two
 | 
				
			||||||
 | 
					 *   concurrent threads must not use both the read functions
 | 
				
			||||||
 | 
					 * - read/write return True on success and False if the message could not be
 | 
				
			||||||
 | 
					 *   read/written because the queue is empty/full
 | 
				
			||||||
 | 
					 * - the size of the messageQueue and the type of the
 | 
				
			||||||
 | 
					 *   messageQueue_QueuedMessage are defined in config_message_queue.h
 | 
				
			||||||
 | 
					 * - only one messageQueue can be used in a project
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "boolean.h"
 | 
				
			||||||
 | 
					#include "config_message_queue.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void    messageQueue_init   (void);
 | 
				
			||||||
 | 
					void    messageQueue_cleanup(void);
 | 
				
			||||||
 | 
					Boolean messageQueue_isEmpty(void);
 | 
				
			||||||
 | 
					Boolean messageQueue_isFull (void);
 | 
				
			||||||
 | 
					Boolean messageQueue_read   (messageQueue_QueuedMessage* pMessage);
 | 
				
			||||||
 | 
					Boolean messageQueue_write  (messageQueue_QueuedMessage message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										108
									
								
								firmware/pwm_channels.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								firmware/pwm_channels.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file pwm_channels.c
 | 
				
			||||||
 | 
					 * \brief Manages the values of the displayed channels.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: pwm_channels.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pwm_channels.h"
 | 
				
			||||||
 | 
					#include "pwm_timer.h"
 | 
				
			||||||
 | 
					#include "config_pwm_timer_impl.h"
 | 
				
			||||||
 | 
					#include "message_queue.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Structure to contain the state of one channel */
 | 
				
			||||||
 | 
					typedef struct S_pwm_Channels_ChannelBrightness {
 | 
				
			||||||
 | 
					    pwm_Channels_Bitfield field; /**< Bitfield resembling one channel */
 | 
				
			||||||
 | 
					    pwm_Timer_Cycles      cycle; /**< Number of on-cycles */
 | 
				
			||||||
 | 
					} pwm_Channels_ChannelBrightness;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize channels. Basically, only the PWM-timer is started.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void pwm_Channels_init(void) {
 | 
				
			||||||
 | 
					    pwm_Timer_init();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clean up channels. Basically, the PWM-timer gets cleaned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void pwm_Channels_cleanup(void) {
 | 
				
			||||||
 | 
					    pwm_Timer_cleanup();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate the Channels_Message. Requires the channel-list to be sorted by
 | 
				
			||||||
 | 
					 * cycles.
 | 
				
			||||||
 | 
					 * \param channels Array of the channels.
 | 
				
			||||||
 | 
					 * \return Current message.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static pwm_Channels_Message pwm_Channels_Message_get(pwm_Channels_ChannelBrightness channels[CHANNELS]) {
 | 
				
			||||||
 | 
					    int j;
 | 
				
			||||||
 | 
					    pwm_Channels_StepCounter i= 0;
 | 
				
			||||||
 | 
					    pwm_Channels_Message message;
 | 
				
			||||||
 | 
					    message.step[i].field = 0;
 | 
				
			||||||
 | 
					    for (j = 0; j < CHANNELS; j++) {
 | 
				
			||||||
 | 
					        message.step[i].field |= channels[j].field;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    message.step[i].cycle= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (j = 0; j < CHANNELS; j++) {
 | 
				
			||||||
 | 
					        if(channels[j].cycle == message.step[i].cycle) {
 | 
				
			||||||
 | 
					            message.step[i].field&= ~channels[j].field;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            message.step[i].cycle= channels[j].cycle;
 | 
				
			||||||
 | 
					            i++;
 | 
				
			||||||
 | 
					            message.step[i]= message.step[i-1];
 | 
				
			||||||
 | 
					            message.step[i].field&= ~channels[j].field;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    message.step[i].cycle= pwm_Timer_Cycles_Max;
 | 
				
			||||||
 | 
					    return message;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate number of cycles from a brightness.
 | 
				
			||||||
 | 
					 * \param brightness The brightness.
 | 
				
			||||||
 | 
					 * \return The number of cycles.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					pwm_Timer_Cycles pwm_Channels_BrightnessToCycles(pwm_Channels_Brightness brightness) {
 | 
				
			||||||
 | 
					    return brightness * brightness;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Compare the number of cycles in two channels. This is needed for the
 | 
				
			||||||
 | 
					 * qsort-call in pwm_Channels_show().
 | 
				
			||||||
 | 
					 * \param cmp1 First channel.
 | 
				
			||||||
 | 
					 * \param cmp2 Second channel.
 | 
				
			||||||
 | 
					 * \return A value <0 if cmp1 is smaller than cmp2, 0 if they are of the same
 | 
				
			||||||
 | 
					 * length and a value >0 if cmp1 is larger than cmp2.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int pwm_Channels_CompareChannels(const void * cmp1, const void * cmp2) {
 | 
				
			||||||
 | 
					    return ((const pwm_Channels_ChannelBrightness*)cmp1)->cycle - ((const pwm_Channels_ChannelBrightness*)cmp2)->cycle;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Writes the current pattern to the message-queue. The pattern is built from
 | 
				
			||||||
 | 
					 * the state of all channels.
 | 
				
			||||||
 | 
					 * \param channels Array with the channel-states.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void pwm_Channels_show(pwm_Channels channels) {
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    pwm_Channels_Message message;
 | 
				
			||||||
 | 
					    pwm_Channels_ChannelBrightness channel_brightness[CHANNELS];
 | 
				
			||||||
 | 
					    for (i = 0; i < CHANNELS; i++) {
 | 
				
			||||||
 | 
					        channel_brightness[i].field = 1 << i; // 1 << i equals 2^i
 | 
				
			||||||
 | 
					        channel_brightness[i].cycle = pwm_Channels_BrightnessToCycles(channels.channel[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qsort(channel_brightness, CHANNELS, sizeof(pwm_Channels_ChannelBrightness), pwm_Channels_CompareChannels);
 | 
				
			||||||
 | 
					    message= pwm_Channels_Message_get(channel_brightness);
 | 
				
			||||||
 | 
					    while(!messageQueue_write(message)) {
 | 
				
			||||||
 | 
					        pwm_Timer_idle();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										39
									
								
								firmware/pwm_channels.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								firmware/pwm_channels.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					#ifndef pwm_Channels_h
 | 
				
			||||||
 | 
					#define pwm_Channels_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file pwm_channels.h
 | 
				
			||||||
 | 
					 * \brief Manages the values of the displayed channels.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: pwm_channels.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - display the specified channels for a cycle of pwm_timer
 | 
				
			||||||
 | 
					 * - before using the function show, init must be called
 | 
				
			||||||
 | 
					 * - for every cycle of pwm_timer, show must be called
 | 
				
			||||||
 | 
					 * - show buffers the selected channels, so it returns immediatly, as long as
 | 
				
			||||||
 | 
					 *   the internal buffer is not full
 | 
				
			||||||
 | 
					 * - when the buffer is full the function blocks until another pwm_timer cycle
 | 
				
			||||||
 | 
					 *   has processed the current channels
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include "channels.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Type to contain the brightness of one channel. */
 | 
				
			||||||
 | 
					typedef uint8_t pwm_Channels_Brightness;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Definition of the maximum brightness. */
 | 
				
			||||||
 | 
					enum { pwm_Channels_Brightness_Max = 31 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Structure to contain the state of several channels. */
 | 
				
			||||||
 | 
					typedef struct S_pwm_Channels {
 | 
				
			||||||
 | 
					  pwm_Channels_Brightness channel[CHANNELS]; /**< Array of channels. */
 | 
				
			||||||
 | 
					} pwm_Channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_Channels_init(void);
 | 
				
			||||||
 | 
					void pwm_Channels_cleanup(void);
 | 
				
			||||||
 | 
					void pwm_Channels_show(pwm_Channels channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										139
									
								
								firmware/pwm_timer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								firmware/pwm_timer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file pwm_timer.c
 | 
				
			||||||
 | 
					 * \brief Controls the actual PWM-output.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: pwm_timer.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					#include <avr/interrupt.h>
 | 
				
			||||||
 | 
					#include <avr/pgmspace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "boolean.h"
 | 
				
			||||||
 | 
					#include "message_queue.h"
 | 
				
			||||||
 | 
					#include "pwm_timer.h"
 | 
				
			||||||
 | 
					#include "config_pwm_timer_impl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Structure to contain the global data for the timer. */
 | 
				
			||||||
 | 
					typedef struct S_pwm_Timer_GlobalData {
 | 
				
			||||||
 | 
					    pwm_Channels_Message     message[2]; /**< Array of two messages */
 | 
				
			||||||
 | 
					    pwm_Channels_Message*    pActive; /**< Pointer to the active message */
 | 
				
			||||||
 | 
					    pwm_Channels_Message*    pRead; /**< Pointer to the message to read */
 | 
				
			||||||
 | 
					    pwm_Channels_StepCounter step; /**< Current step in the cycle */
 | 
				
			||||||
 | 
					    pwm_Timer_Cycles         currentCycle; /**< Current cycle */
 | 
				
			||||||
 | 
					    Boolean                  readDone; /**< Indicates if something is read from the queue */
 | 
				
			||||||
 | 
					} pwm_Timer_GlobalData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static pwm_Timer_GlobalData m_data; /**< Global data for the timer. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize the PWM-Timer. Sets basic values, starts the timer and
 | 
				
			||||||
 | 
					 * initializes output-pins.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void pwm_Timer_init(void) {
 | 
				
			||||||
 | 
					    messageQueue_init();
 | 
				
			||||||
 | 
					    m_data.step=           0;
 | 
				
			||||||
 | 
					    m_data.currentCycle=   0;
 | 
				
			||||||
 | 
					    m_data.pActive=        &m_data.message[0];
 | 
				
			||||||
 | 
					    m_data.pRead=          &m_data.message[1];
 | 
				
			||||||
 | 
					    m_data.readDone=       False;
 | 
				
			||||||
 | 
					    m_data.pActive->step[0].cycle= pwm_Channels_Brightness_Max;
 | 
				
			||||||
 | 
					    m_data.pActive->step[0].field=      0;
 | 
				
			||||||
 | 
					    /* clk/64 prescaling, CTC mode */
 | 
				
			||||||
 | 
					    /* enable timer1 overflow (=output compare 1a) */
 | 
				
			||||||
 | 
					    TCCR1B= _BV(CS11) | _BV(CS10) | _BV(WGM12);
 | 
				
			||||||
 | 
					    TCCR1A= 0;
 | 
				
			||||||
 | 
					    TIMSK|= _BV(OCIE1A);
 | 
				
			||||||
 | 
					    /* load initial delay */
 | 
				
			||||||
 | 
					    OCR1A=  pwm_Timer_Cycles_Max;
 | 
				
			||||||
 | 
					    /* initialize output pin */
 | 
				
			||||||
 | 
					    DDRC = (1 << CHANNELS) - 1; // set all used channel-pins to output
 | 
				
			||||||
 | 
					    PORTC = 0;
 | 
				
			||||||
 | 
					    sei();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clean up the timer. Basically, the message-queue is cleaned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void pwm_Timer_cleanup(void) {
 | 
				
			||||||
 | 
					    messageQueue_cleanup();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Do nothing.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void pwm_Timer_idle(void)
 | 
				
			||||||
 | 
					{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sleeps the required number of cycles. There are two possible ways of
 | 
				
			||||||
 | 
					 * sleeping: 'active' and 'passive'. If we are required to sleep less than the
 | 
				
			||||||
 | 
					 * number of cycles defined in pwm_Timer_Cycles_SleepMax, we execute an empty
 | 
				
			||||||
 | 
					 * loop until we are ready (active sleeping). Otherwise, we set the timer to
 | 
				
			||||||
 | 
					 * wake us after the given number of cycles (passive sleeping).
 | 
				
			||||||
 | 
					 * \param sleep Number of cycles.
 | 
				
			||||||
 | 
					 * \return True if we slept 'actively' (doing the while-loop), otherwise false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static Boolean pwm_Timer_sleep(pwm_Timer_Cycles sleep) {
 | 
				
			||||||
 | 
					    Boolean sleepDone= False;
 | 
				
			||||||
 | 
					    if((sleep < pwm_Timer_Cycles_SleepMax)) {
 | 
				
			||||||
 | 
					        while (TCNT1 < sleep)
 | 
				
			||||||
 | 
					        {}
 | 
				
			||||||
 | 
					        sleepDone= True;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        OCR1A= sleep;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return sleepDone;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Switch the output-pins to the given pattern.
 | 
				
			||||||
 | 
					 * \param field 8-bit output-pattern.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void pwm_Timer_switchLed(pwm_Channels_Bitfield field) {
 | 
				
			||||||
 | 
					    PORTC= field;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Timer interrupt routine. Determines the pattern to set and handles the times
 | 
				
			||||||
 | 
					 * to do PWM.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SIGNAL(SIG_OUTPUT_COMPARE1A) {
 | 
				
			||||||
 | 
					    pwm_Timer_Cycles sleep= pwm_Timer_Cycles_Max;
 | 
				
			||||||
 | 
					    OCR1A= pwm_Timer_Cycles_Max;
 | 
				
			||||||
 | 
					    sei();
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        if((m_data.step == pwm_Channels_StepCounter_Max) || (m_data.currentCycle == pwm_Timer_Cycles_Max)) {
 | 
				
			||||||
 | 
					            if(m_data.readDone) {
 | 
				
			||||||
 | 
					                pwm_Channels_Message* pSwap= m_data.pActive;
 | 
				
			||||||
 | 
					                m_data.pActive= m_data.pRead;
 | 
				
			||||||
 | 
					                m_data.pRead=   pSwap;
 | 
				
			||||||
 | 
					                m_data.readDone= False;
 | 
				
			||||||
 | 
					                m_data.currentCycle= 0;
 | 
				
			||||||
 | 
					                m_data.step= 0;
 | 
				
			||||||
 | 
					                sleep= 0;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                /* error could not read a new channels message in a whole cycle */
 | 
				
			||||||
 | 
					                /* wait a complete cycle for the next message */
 | 
				
			||||||
 | 
					                //sleep= pwm_Timer_Cycles_Max;
 | 
				
			||||||
 | 
					                m_data.currentCycle= 0;
 | 
				
			||||||
 | 
					                m_data.step= 0;
 | 
				
			||||||
 | 
					                sleep= 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            pwm_Timer_switchLed(m_data.pActive->step[m_data.step].field);
 | 
				
			||||||
 | 
					            sleep= m_data.pActive->step[m_data.step].cycle - m_data.currentCycle;
 | 
				
			||||||
 | 
					            m_data.currentCycle= m_data.pActive->step[m_data.step].cycle;
 | 
				
			||||||
 | 
					            m_data.step++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } while(pwm_Timer_sleep(sleep));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!m_data.readDone && (sleep > pwm_Timer_Cycles_ReadMin)) {
 | 
				
			||||||
 | 
					        if(messageQueue_read(m_data.pRead)) {
 | 
				
			||||||
 | 
					            m_data.readDone= True;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										70
									
								
								firmware/pwm_timer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								firmware/pwm_timer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					#ifndef pwm_timer_h
 | 
				
			||||||
 | 
					#define pwm_timer_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file pwm_timer.h
 | 
				
			||||||
 | 
					 * \brief Controls the actual PWM-output.
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: pwm_timer.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - read and process the pwm_Channels_Message from the messageQueue (written
 | 
				
			||||||
 | 
					 *   by pwm_Channels)
 | 
				
			||||||
 | 
					 * - use a timed interrupt to switch the led at a specified processor cycle
 | 
				
			||||||
 | 
					 * - init starts the processing and the timer
 | 
				
			||||||
 | 
					 * - idle is called by the pwm_Channels when the internal buffer is full
 | 
				
			||||||
 | 
					 * - at every pwm_timer cycle the leds can be switched in up to four steps
 | 
				
			||||||
 | 
					 *   every step defines which leds are switched on/off and up to which
 | 
				
			||||||
 | 
					 *   processor cycle the status is hold so the brightness for the three leds
 | 
				
			||||||
 | 
					 *   can be switched independently
 | 
				
			||||||
 | 
					 * - example:
 | 
				
			||||||
 | 
					 *   - start with all leds for 10 cycles:
 | 
				
			||||||
 | 
					 *     \code
 | 
				
			||||||
 | 
					 *     step[0]= {10, 1|2|4};
 | 
				
			||||||
 | 
					 *     \endcode
 | 
				
			||||||
 | 
					 *   - switch off the red led for further 10 cycles
 | 
				
			||||||
 | 
					 *     \code
 | 
				
			||||||
 | 
					 *     step[1]= {20,   2|4};
 | 
				
			||||||
 | 
					 *     \endcode
 | 
				
			||||||
 | 
					 *   - switch off the green led for further 10 cycles
 | 
				
			||||||
 | 
					 *     \code
 | 
				
			||||||
 | 
					 *     step[2]= {30,     4};
 | 
				
			||||||
 | 
					 *     \endcode
 | 
				
			||||||
 | 
					 *   - switch off all leds for the remaining time
 | 
				
			||||||
 | 
					 *     \code
 | 
				
			||||||
 | 
					 *     step[3]= {pwm_Timer_Cycles_Max, 0};
 | 
				
			||||||
 | 
					 *     \endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pwm_channels.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 8-bit-field to contain the state of the channels. */
 | 
				
			||||||
 | 
					typedef uint8_t pwm_Channels_Bitfield;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Value to count the steps in one channel. */
 | 
				
			||||||
 | 
					typedef uint8_t pwm_Channels_StepCounter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Contains a number of controller-cycles. */
 | 
				
			||||||
 | 
					typedef uint16_t pwm_Timer_Cycles;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Definition of the maximum number of steps. */
 | 
				
			||||||
 | 
					enum{pwm_Channels_StepCounter_Max= CHANNELS + 1};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Structure to contain one step. */
 | 
				
			||||||
 | 
					typedef struct S_pwm_Channels_Step {
 | 
				
			||||||
 | 
					    pwm_Timer_Cycles cycle; /**< Number of cycles to complete this step. */
 | 
				
			||||||
 | 
					    pwm_Channels_Bitfield field; /**< The state of all channels. */
 | 
				
			||||||
 | 
					} pwm_Channels_Step;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Structure to contain an array of steps. */
 | 
				
			||||||
 | 
					typedef struct S_pwm_Channels_Message {
 | 
				
			||||||
 | 
					    pwm_Channels_Step step[pwm_Channels_StepCounter_Max]; /**< Array of steps. */
 | 
				
			||||||
 | 
					} pwm_Channels_Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_Timer_init(void);
 | 
				
			||||||
 | 
					void pwm_Timer_cleanup(void);
 | 
				
			||||||
 | 
					void pwm_Timer_idle(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										170
									
								
								firmware/usbconfig.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								firmware/usbconfig.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
				
			|||||||
 | 
					/* Name: usbconfig.h
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2005-04-01
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: usbconfig.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __usbconfig_h_included__
 | 
				
			||||||
 | 
					#define __usbconfig_h_included__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file usbconfig.h
 | 
				
			||||||
 | 
					 * \brief Configuration of the USB-driver.
 | 
				
			||||||
 | 
					 * \version $Id: usbconfig.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					This file contains parts of the USB driver which can be configured and can or
 | 
				
			||||||
 | 
					must be adapted to your hardware.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please note that the usbdrv contains a usbconfig-prototype.h file now. We
 | 
				
			||||||
 | 
					recommend that you use that file as a template because it will always list
 | 
				
			||||||
 | 
					the newest features and options.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ---------------------------- Hardware Config ---------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_CFG_IOPORTNAME      B
 | 
				
			||||||
 | 
					/* This is the port where the USB bus is connected. When you configure it to
 | 
				
			||||||
 | 
					 * "PORTB", the registers PORTB, PINB (=PORTB-2) and DDRB (=PORTB-1) will be
 | 
				
			||||||
 | 
					 * used.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DMINUS_BIT      0
 | 
				
			||||||
 | 
					/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 | 
				
			||||||
 | 
					 * This MUST be bit 0 or 7. All other values will result in a compile error!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DPLUS_BIT       1
 | 
				
			||||||
 | 
					/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 | 
				
			||||||
 | 
					 * This may be any bit in the port. Please note that D+ must also be connected
 | 
				
			||||||
 | 
					 * to interrupt pin INT0!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* #define USB_CFG_PULLUP_IOPORTNAME   B */
 | 
				
			||||||
 | 
					/* This is the port where the USB D- pullup resistor is connected. When you
 | 
				
			||||||
 | 
					 * configure it to "PORTB", the registers PORTB and DDRB (=PORTB-1) will be
 | 
				
			||||||
 | 
					 * used. If this constant is defined, the macros usbDeviceConnect() and
 | 
				
			||||||
 | 
					 * usbDeviceDisconnect will be available.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define USB_CFG_PULLUP_BIT          2 */
 | 
				
			||||||
 | 
					/* This is the bit number in USB_CFG_PULLUP_IOPORT where the USB D- 1.5 kOhm
 | 
				
			||||||
 | 
					 * pullup resistor is connected instead of VBUS. This may be any bit in
 | 
				
			||||||
 | 
					 * the port.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* --------------------------- Functional Range ---------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_CFG_HAVE_INTRIN_ENDPOINT    0
 | 
				
			||||||
 | 
					/* Define this to 1 if you want to compile a version with two endpoints: The
 | 
				
			||||||
 | 
					 * default control endpoint 0 and an interrupt-in endpoint 1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_HALT          0
 | 
				
			||||||
 | 
					/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
 | 
				
			||||||
 | 
					 * for endpoint 1 (interrupt endpoint). Although you may not need this feature,
 | 
				
			||||||
 | 
					 * it is required by the standard. We have made it a config option because it
 | 
				
			||||||
 | 
					 * bloats the code considerably.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_INTR_POLL_INTERVAL      10
 | 
				
			||||||
 | 
					/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
 | 
				
			||||||
 | 
					 * interval. The value is in milliseconds and must not be less than 10 ms for
 | 
				
			||||||
 | 
					 * low speed devices.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IS_SELF_POWERED         1
 | 
				
			||||||
 | 
					/* Define this to 1 if the device has its own power supply. Set it to 0 if the
 | 
				
			||||||
 | 
					 * device is powered from the USB bus.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_MAX_BUS_POWER           20
 | 
				
			||||||
 | 
					/* Set this variable to the maximum USB bus power consumption of your device.
 | 
				
			||||||
 | 
					 * The value is in milliamperes. [It will be divided by two since USB
 | 
				
			||||||
 | 
					 * communicates power requirements in units of 2 mA.]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_SAMPLE_EXACT            0
 | 
				
			||||||
 | 
					/* This variable affects Sampling Jitter for USB receiving. When it is 0, the
 | 
				
			||||||
 | 
					 * driver guarantees a sampling window of 1/2 bit. The USB spec requires
 | 
				
			||||||
 | 
					 * that the receiver has at most 1/4 bit sampling window. The 1/2 bit window
 | 
				
			||||||
 | 
					 * should still work reliably enough because we work at low speed. If you want
 | 
				
			||||||
 | 
					 * to meet the spec, set this value to 1. This will unroll a loop which
 | 
				
			||||||
 | 
					 * results in bigger code size.
 | 
				
			||||||
 | 
					 * If you have problems with long cables, try setting this value to 1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_FN_WRITE      1
 | 
				
			||||||
 | 
					/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
 | 
				
			||||||
 | 
					 * transfers. Set it to 0 if you don't need it and want to save a couple of
 | 
				
			||||||
 | 
					 * bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_FN_READ       1
 | 
				
			||||||
 | 
					/* Set this to 1 if you need to send control replies which are generated
 | 
				
			||||||
 | 
					 * "on the fly" when usbFunctionRead() is called. If you only want to send
 | 
				
			||||||
 | 
					 * data from a static buffer, set it to 0 and return the data from
 | 
				
			||||||
 | 
					 * usbFunctionSetup(). This saves a couple of bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* -------------------------- Device Description --------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define  USB_CFG_VENDOR_ID  0xc0, 0x16  /* 5824 in dec, stands for VOTI */
 | 
				
			||||||
 | 
					/* USB vendor ID for the device, low byte first. If you have registered your
 | 
				
			||||||
 | 
					 * own Vendor ID, define it here. Otherwise you use obdev's free shared
 | 
				
			||||||
 | 
					 * VID/PID pair. Be sure to read USBID-License.txt for rules!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_ID   0xdc, 0x05  /* 1500 in dec, obdev's free PID */
 | 
				
			||||||
 | 
					/* This is the ID of the product, low byte first. It is interpreted in the
 | 
				
			||||||
 | 
					 * scope of the vendor ID. If you have registered your own VID with usb.org
 | 
				
			||||||
 | 
					 * or if you have licensed a PID from somebody else, define it here. Otherwise
 | 
				
			||||||
 | 
					 * you use obdev's free shared VID/PID pair. Be sure to read the rules in
 | 
				
			||||||
 | 
					 * USBID-License.txt!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_VERSION  0x00, 0x01
 | 
				
			||||||
 | 
					/* Version number of the device: Minor number first, then major number.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_VENDOR_NAME     'w', 'w', 'w', '.', 's', 'c', 'h', 'a', 't', 'e', 'n', 's', 'e', 'i', 't', 'e', '.', 'd', 'e'
 | 
				
			||||||
 | 
					#define USB_CFG_VENDOR_NAME_LEN 19
 | 
				
			||||||
 | 
					/* These two values define the vendor name returned by the USB device. The name
 | 
				
			||||||
 | 
					 * must be given as a list of characters under single quotes. The characters
 | 
				
			||||||
 | 
					 * are interpreted as Unicode (UTF-16) entities.
 | 
				
			||||||
 | 
					 * If you don't want a vendor name string, undefine these macros.
 | 
				
			||||||
 | 
					 * ALWAYS define a vendor name containing your Internet domain name if you use
 | 
				
			||||||
 | 
					 * obdev's free shared VID/PID pair. See the file USBID-License.txt for
 | 
				
			||||||
 | 
					 * details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_NAME     'U', 'S', 'B', '-', 'L', 'E', 'D', '-', 'F', 'a', 'd', 'e', 'r'
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_NAME_LEN 13
 | 
				
			||||||
 | 
					/* Same as above for the device name. If you don't want a device name, undefine
 | 
				
			||||||
 | 
					 * the macros. See the file USBID-License.txt before you assign a name.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_SERIAL_NUMBER_LENGTH  0
 | 
				
			||||||
 | 
					/* Set this define to the number of charcters in the serial number if your
 | 
				
			||||||
 | 
					 * device should have a serial number to uniquely identify each hardware
 | 
				
			||||||
 | 
					 * instance. You must supply the serial number in a string descriptor with the
 | 
				
			||||||
 | 
					 * name "usbCfgSerialNumberStringDescriptor", e.g.:
 | 
				
			||||||
 | 
					 * #define USB_CFG_SERIAL_NUMBER_LENGTH  5
 | 
				
			||||||
 | 
					 * int usbCfgSerialNumberStringDescriptor[] PROGMEM = {
 | 
				
			||||||
 | 
					 *     USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LENGTH),
 | 
				
			||||||
 | 
					 *     '1', '2', '3', '4', '5'
 | 
				
			||||||
 | 
					 * };
 | 
				
			||||||
 | 
					 * See usbdrv.h for more information about the USB_STRING_DESCRIPTOR_HEADER()
 | 
				
			||||||
 | 
					 * macro or usbdrv.c for example string descriptors.
 | 
				
			||||||
 | 
					 * You may want to put "usbCfgSerialNumberStringDescriptor" at a constant
 | 
				
			||||||
 | 
					 * flash memory address (with magic linker commands) so that you don't need
 | 
				
			||||||
 | 
					 * to recompile if you change it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_CLASS    0xff
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_SUBCLASS 0
 | 
				
			||||||
 | 
					/* See USB specification if you want to conform to an existing device class.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_INTERFACE_CLASS     0
 | 
				
			||||||
 | 
					#define USB_CFG_INTERFACE_SUBCLASS  0
 | 
				
			||||||
 | 
					#define USB_CFG_INTERFACE_PROTOCOL  0
 | 
				
			||||||
 | 
					/* See USB specification if you want to conform to an existing device class or
 | 
				
			||||||
 | 
					 * protocol.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    0   /* total length of report descriptor */
 | 
				
			||||||
 | 
					/* Define this to the length of the HID report descriptor, if you implement
 | 
				
			||||||
 | 
					 * an HID device. Otherwise don't define it or define it to 0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __usbconfig_h_included__ */
 | 
				
			||||||
							
								
								
									
										115
									
								
								firmware/usbdrv/Changelog.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								firmware/usbdrv/Changelog.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
				
			|||||||
 | 
					This file documents changes in the firmware-only USB driver for atmel's AVR
 | 
				
			||||||
 | 
					microcontrollers. New entries are always appended to the end of the file.
 | 
				
			||||||
 | 
					Scroll down to the bottom to see the most recent changes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2005-04-01:
 | 
				
			||||||
 | 
					  - Implemented endpoint 1 as interrupt-in endpoint.
 | 
				
			||||||
 | 
					  - Moved all configuration options to usbconfig.h which is not part of the
 | 
				
			||||||
 | 
					    driver.
 | 
				
			||||||
 | 
					  - Changed interface for usbVendorSetup().
 | 
				
			||||||
 | 
					  - Fixed compatibility with ATMega8 device.
 | 
				
			||||||
 | 
					  - Various minor optimizations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2005-04-11:
 | 
				
			||||||
 | 
					  - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead()
 | 
				
			||||||
 | 
					    and usbFunctionWrite() now. Added configuration options to choose which
 | 
				
			||||||
 | 
					    of these functions to compile in.
 | 
				
			||||||
 | 
					  - Assembler module delivers receive data non-inverted now.
 | 
				
			||||||
 | 
					  - Made register and bit names compatible with more AVR devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2005-05-03:
 | 
				
			||||||
 | 
					  - Allow address of usbRxBuf on any memory page as long as the buffer does
 | 
				
			||||||
 | 
					    not cross 256 byte page boundaries.
 | 
				
			||||||
 | 
					  - Better device compatibility: works with Mega88 now.
 | 
				
			||||||
 | 
					  - Code optimization in debugging module.
 | 
				
			||||||
 | 
					  - Documentation updates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2006-01-02:
 | 
				
			||||||
 | 
					  - Added (free) default Vendor- and Product-IDs bought from voti.nl.
 | 
				
			||||||
 | 
					  - Added USBID-License.txt file which defines the rules for using the free
 | 
				
			||||||
 | 
					    shared VID/PID pair.
 | 
				
			||||||
 | 
					  - Added Readme.txt to the usbdrv directory which clarifies administrative
 | 
				
			||||||
 | 
					    issues.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2006-01-25:
 | 
				
			||||||
 | 
					  - Added "configured state" to become more standards compliant.
 | 
				
			||||||
 | 
					  - Added "HALT" state for interrupt endpoint.
 | 
				
			||||||
 | 
					  - Driver passes the "USB Command Verifier" test from usb.org now.
 | 
				
			||||||
 | 
					  - Made "serial number" a configuration option.
 | 
				
			||||||
 | 
					  - Minor optimizations, we now recommend compiler option "-Os" for best
 | 
				
			||||||
 | 
					    results.
 | 
				
			||||||
 | 
					  - Added a version number to usbdrv.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2006-02-03:
 | 
				
			||||||
 | 
					  - New configuration variable USB_BUFFER_SECTION for the memory section where
 | 
				
			||||||
 | 
					    the USB rx buffer will go. This defaults to ".bss" if not defined. Since
 | 
				
			||||||
 | 
					    this buffer MUST NOT cross 256 byte pages (not even touch a page at the
 | 
				
			||||||
 | 
					    end), the user may want to pass a linker option similar to
 | 
				
			||||||
 | 
					    "-Wl,--section-start=.mybuffer=0x800060".
 | 
				
			||||||
 | 
					  - Provide structure for usbRequest_t.
 | 
				
			||||||
 | 
					  - New defines for USB constants.
 | 
				
			||||||
 | 
					  - Prepared for HID implementations.
 | 
				
			||||||
 | 
					  - Increased data size limit for interrupt transfers to 8 bytes.
 | 
				
			||||||
 | 
					  - New macro usbInterruptIsReady() to query interrupt buffer state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2006-02-18:
 | 
				
			||||||
 | 
					  - Ensure that the data token which is sent as an ack to an OUT transfer is
 | 
				
			||||||
 | 
					    always zero sized. This fixes a bug where the host reports an error after
 | 
				
			||||||
 | 
					    sending an out transfer to the device, although all data arrived at the
 | 
				
			||||||
 | 
					    device.
 | 
				
			||||||
 | 
					  - Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite().
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Release 2006-02-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - Give a compiler warning when compiling with debugging turned on.
 | 
				
			||||||
 | 
					  - Added Oleg Semyonov's changes for IAR-cc compatibility.
 | 
				
			||||||
 | 
					  - Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect()
 | 
				
			||||||
 | 
					    (also thanks to Oleg!).
 | 
				
			||||||
 | 
					  - Rearranged tests in usbPoll() to save a couple of instructions in the most
 | 
				
			||||||
 | 
					    likely case that no actions are pending.
 | 
				
			||||||
 | 
					  - We need a delay between the SET ADDRESS request until the new address
 | 
				
			||||||
 | 
					    becomes active. This delay was handled in usbPoll() until now. Since the
 | 
				
			||||||
 | 
					    spec says that the delay must not exceed 2ms, previous versions required
 | 
				
			||||||
 | 
					    aggressive polling during the enumeration phase. We have now moved the
 | 
				
			||||||
 | 
					    handling of the delay into the interrupt routine.
 | 
				
			||||||
 | 
					  - We must not reply with NAK to a SETUP transaction. We can only achieve this
 | 
				
			||||||
 | 
					    by making sure that the rx buffer is empty when SETUP tokens are expected.
 | 
				
			||||||
 | 
					    We therefore don't pass zero sized data packets from the status phase of
 | 
				
			||||||
 | 
					    a transfer to usbPoll(). This change MAY cause troubles if you rely on
 | 
				
			||||||
 | 
					    receiving a less than 8 bytes long packet in usbFunctionWrite() to
 | 
				
			||||||
 | 
					    identify the end of a transfer. usbFunctionWrite() will NEVER be called
 | 
				
			||||||
 | 
					    with a zero length.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Release 2006-03-14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - Improved IAR C support: tiny memory model, more devices
 | 
				
			||||||
 | 
					  - Added template usbconfig.h file under the name usbconfig-prototype.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Release 2006-03-26
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - Added provision for one more interrupt-in endpoint (endpoint 3).
 | 
				
			||||||
 | 
					  - Added provision for one interrupt-out endpoint (endpoint 1).
 | 
				
			||||||
 | 
					  - Added flowcontrol macros for USB.
 | 
				
			||||||
 | 
					  - Added provision for custom configuration descriptor.
 | 
				
			||||||
 | 
					  - Allow ANY two port bits for D+ and D-.
 | 
				
			||||||
 | 
					  - Merged (optional) receive endpoint number into global usbRxToken variable.
 | 
				
			||||||
 | 
					  - Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the
 | 
				
			||||||
 | 
					    variable name from the single port letter instead of computing the address
 | 
				
			||||||
 | 
					    of related ports from the output-port address.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Release 2006-06-26
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the
 | 
				
			||||||
 | 
					    new features.
 | 
				
			||||||
 | 
					  - Removed "#warning" directives because IAR does not understand them. Use
 | 
				
			||||||
 | 
					    unused static variables instead to generate a warning.
 | 
				
			||||||
 | 
					  - Do not include <avr/io.h> when compiling with IAR.
 | 
				
			||||||
 | 
					  - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each
 | 
				
			||||||
 | 
					    USB descriptor should be handled. It is now possible to provide descriptor
 | 
				
			||||||
 | 
					    data in Flash, RAM or dynamically at runtime.
 | 
				
			||||||
 | 
					  - STALL is now a status in usbTxLen* instead of a message. We can now conform
 | 
				
			||||||
 | 
					    to the spec and leave the stall status pending until it is cleared.
 | 
				
			||||||
 | 
					  - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the
 | 
				
			||||||
 | 
					    application code to reset data toggling on interrupt pipes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Release 2006-07-18
 | 
				
			||||||
							
								
								
									
										458
									
								
								firmware/usbdrv/License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										458
									
								
								firmware/usbdrv/License.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,458 @@
 | 
				
			|||||||
 | 
					PREFACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Conceiving and understanding a new license is not an easy task. To make things
 | 
				
			||||||
 | 
					easier for both, the author and the licensee, we have decided to base our
 | 
				
			||||||
 | 
					license for the USB driver on an existing license with well-understood
 | 
				
			||||||
 | 
					properties.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Our favorite choice for the base license was the GNU General Public License
 | 
				
			||||||
 | 
					(GPL). However, we cannot use the GNU GPL directly for the following reasons:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(1) It was not intended for projects involving hardware -- we must extend the
 | 
				
			||||||
 | 
					    term "source code" to at least the circuit diagram.
 | 
				
			||||||
 | 
					(2) The GNU GPL does not require publication. Only if a binary is published,
 | 
				
			||||||
 | 
					    it requires that the source is published as well. This is reasonable for
 | 
				
			||||||
 | 
					    software because unpublished software is of little relevance. For projects
 | 
				
			||||||
 | 
					    involving hardware, we want to REQUIRE publication. More than that, we
 | 
				
			||||||
 | 
					    even want to define HOW the publication must be done (files contained,
 | 
				
			||||||
 | 
					    file formats etc).
 | 
				
			||||||
 | 
					(3) As the author of the software, we can distribute it under more than one
 | 
				
			||||||
 | 
					    license. For people who don't want to meet the obligations of the GNU GPL,
 | 
				
			||||||
 | 
					    we want to offer commercial licenses. To avoid a split in revisions of
 | 
				
			||||||
 | 
					    the driver, we need special privileges to distribute contributed
 | 
				
			||||||
 | 
					    modifications under proprietary licenses.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We can not simply modify the GNU GPL and incorporate our changes because the
 | 
				
			||||||
 | 
					Free Software Foundation (FSF) who holds the copyright for the text of the
 | 
				
			||||||
 | 
					GNU GPL does not allow modifications. We therefore set up our own small
 | 
				
			||||||
 | 
					license which incorporates the GNU GPL by reference:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LICENSE FOR PROJECTS BUILT WITH "OBJECTIVE DEVELOPMENT'S
 | 
				
			||||||
 | 
					FIRMWARE-ONLY USB-DRIVER FOR ATMEL'S AVR MICROCONTROLLERS"
 | 
				
			||||||
 | 
					Version 2006-01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I. Definitions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"OBDEV" shall mean OBJECTIVE DEVELOPMENT Software GmbH or any legal successor
 | 
				
			||||||
 | 
					thereof.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"Software Source Code" shall mean the preferred form of the software for
 | 
				
			||||||
 | 
					making modifications to it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"USB Driver" shall mean the Software Source Code for OBDEV's firmware-only
 | 
				
			||||||
 | 
					USB-driver for Atmel's AVR microcontrollers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"Function" shall mean the Software Source Code for all software executed on
 | 
				
			||||||
 | 
					the microcontroller except the USB Driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"Host Software" shall mean the Software Source Code for all software required
 | 
				
			||||||
 | 
					to control the USB device from the USB host running any operating system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"Project" shall mean the USB Driver, the Function, the Host Software, circuit
 | 
				
			||||||
 | 
					diagrams of the controller based hardware and accompanying documentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"source code" shall have the same meaning as the term "Project" above.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"Web Site" shall mean a collection of text and multimedia documents accessible
 | 
				
			||||||
 | 
					worldwide over internet through the HyperText Transfer Protocol (HTTP) on
 | 
				
			||||||
 | 
					TCP port 80 (standard HTTP port).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					II. General License Terms
 | 
				
			||||||
 | 
					The general terms of this license consist of the GNU General Public License
 | 
				
			||||||
 | 
					Version 2 (GNU GPL2) which is hereby incorporated into this section as though
 | 
				
			||||||
 | 
					it were fully set forth here. A copy of the GNU GPL2 is included for your
 | 
				
			||||||
 | 
					convenience in appendix A of this license.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The term "source code" in the GNU GPL2 is to be understood as defined in
 | 
				
			||||||
 | 
					section I above. If any term or definition in section I, III, IV or V
 | 
				
			||||||
 | 
					conflicts with the GNU GPL2, the term or definition in section I, III, IV or
 | 
				
			||||||
 | 
					V has precedence of the GNU GPL2.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					III. Distribution of the Project
 | 
				
			||||||
 | 
					The distributed form of a Project must contain at least the following files:
 | 
				
			||||||
 | 
					(a) Software Source Code files for the USB Driver, the Function and the Host
 | 
				
			||||||
 | 
					    Software.
 | 
				
			||||||
 | 
					(b) Circuit diagrams for the hardware in PDF, PNG or GIF image file format.
 | 
				
			||||||
 | 
					(c) A file with name "Readme.txt" in ASCII format with at least the following
 | 
				
			||||||
 | 
					    content (in English language):
 | 
				
			||||||
 | 
					    - An explanation what the Project does.
 | 
				
			||||||
 | 
					    - What to do with the distributed files (installation procedure etc.).
 | 
				
			||||||
 | 
					    - A reference to Objective Development's USB driver.
 | 
				
			||||||
 | 
					    - Your (author's) name and contact information. E-mail and/or URL is
 | 
				
			||||||
 | 
					      sufficient.
 | 
				
			||||||
 | 
					(d) Optionally a text file with a description of the circuit diagram, an
 | 
				
			||||||
 | 
					    explanation of special (software) techniques used etc. 
 | 
				
			||||||
 | 
					(e) A copy of this license in a file with the name "License.txt". This copy
 | 
				
			||||||
 | 
					    can be in the "usbdrv" subdirectory which contains the driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IV. Requirement for Publication
 | 
				
			||||||
 | 
					All modifications and derived work (Projects using the USB Driver) MUST be
 | 
				
			||||||
 | 
					distributed (published) as described in section III above on a Web Site. The
 | 
				
			||||||
 | 
					main page must reproduce at least a description of the Project (e.g. as
 | 
				
			||||||
 | 
					contained in the "Readme.txt" file distributed) and a download link for the
 | 
				
			||||||
 | 
					entire Project. The URL of the main page must be submitted to OBDEV. OBDEV
 | 
				
			||||||
 | 
					will provide a mechanism for submitting Project URLs and for publishing
 | 
				
			||||||
 | 
					Projects on their Web Site. The Project must remain available for at least
 | 
				
			||||||
 | 
					twelve (12) months after the initial publication or at least six (6) months
 | 
				
			||||||
 | 
					after a subsequent version of that particular Project has been published.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					V. Author Privileges
 | 
				
			||||||
 | 
					OBDEV reserves the right to distribute the USB Driver and all modified
 | 
				
			||||||
 | 
					versions under other (proprietary) licenses. If you modify the USB Driver
 | 
				
			||||||
 | 
					under the grants of this license, you therefore grant OBDEV (in addition to
 | 
				
			||||||
 | 
					the grants of the GNU GPL2) a worldwide, perpetual, irrevocable royalty free
 | 
				
			||||||
 | 
					license for your modifications. OBDEV shall not automatically gain rights
 | 
				
			||||||
 | 
					other than those of the GNU GPL2 in the other parts of the Project. This
 | 
				
			||||||
 | 
					section V overrides possibly contradicting terms in the GNU GPL2 referenced
 | 
				
			||||||
 | 
					in section II.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					APPENDIX A
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					                       Version 2, June 1991
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					 Everyone is permitted to copy and distribute verbatim copies
 | 
				
			||||||
 | 
					 of this license document, but changing it is not allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            Preamble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The licenses for most software are designed to take away your
 | 
				
			||||||
 | 
					freedom to share and change it.  By contrast, the GNU General Public
 | 
				
			||||||
 | 
					License is intended to guarantee your freedom to share and change free
 | 
				
			||||||
 | 
					software--to make sure the software is free for all its users.  This
 | 
				
			||||||
 | 
					General Public License applies to most of the Free Software
 | 
				
			||||||
 | 
					Foundation's software and to any other program whose authors commit to
 | 
				
			||||||
 | 
					using it.  (Some other Free Software Foundation software is covered by
 | 
				
			||||||
 | 
					the GNU Library General Public License instead.)  You can apply it to
 | 
				
			||||||
 | 
					your programs, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  When we speak of free software, we are referring to freedom, not
 | 
				
			||||||
 | 
					price.  Our General Public Licenses are designed to make sure that you
 | 
				
			||||||
 | 
					have the freedom to distribute copies of free software (and charge for
 | 
				
			||||||
 | 
					this service if you wish), that you receive source code or can get it
 | 
				
			||||||
 | 
					if you want it, that you can change the software or use pieces of it
 | 
				
			||||||
 | 
					in new free programs; and that you know you can do these things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To protect your rights, we need to make restrictions that forbid
 | 
				
			||||||
 | 
					anyone to deny you these rights or to ask you to surrender the rights.
 | 
				
			||||||
 | 
					These restrictions translate to certain responsibilities for you if you
 | 
				
			||||||
 | 
					distribute copies of the software, or if you modify it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  For example, if you distribute copies of such a program, whether
 | 
				
			||||||
 | 
					gratis or for a fee, you must give the recipients all the rights that
 | 
				
			||||||
 | 
					you have.  You must make sure that they, too, receive or can get the
 | 
				
			||||||
 | 
					source code.  And you must show them these terms so they know their
 | 
				
			||||||
 | 
					rights.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  We protect your rights with two steps: (1) copyright the software, and
 | 
				
			||||||
 | 
					(2) offer you this license which gives you legal permission to copy,
 | 
				
			||||||
 | 
					distribute and/or modify the software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Also, for each author's protection and ours, we want to make certain
 | 
				
			||||||
 | 
					that everyone understands that there is no warranty for this free
 | 
				
			||||||
 | 
					software.  If the software is modified by someone else and passed on, we
 | 
				
			||||||
 | 
					want its recipients to know that what they have is not the original, so
 | 
				
			||||||
 | 
					that any problems introduced by others will not reflect on the original
 | 
				
			||||||
 | 
					authors' reputations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Finally, any free program is threatened constantly by software
 | 
				
			||||||
 | 
					patents.  We wish to avoid the danger that redistributors of a free
 | 
				
			||||||
 | 
					program will individually obtain patent licenses, in effect making the
 | 
				
			||||||
 | 
					program proprietary.  To prevent this, we have made it clear that any
 | 
				
			||||||
 | 
					patent must be licensed for everyone's free use or not licensed at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The precise terms and conditions for copying, distribution and
 | 
				
			||||||
 | 
					modification follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  0. This License applies to any program or other work which contains
 | 
				
			||||||
 | 
					a notice placed by the copyright holder saying it may be distributed
 | 
				
			||||||
 | 
					under the terms of this General Public License.  The "Program", below,
 | 
				
			||||||
 | 
					refers to any such program or work, and a "work based on the Program"
 | 
				
			||||||
 | 
					means either the Program or any derivative work under copyright law:
 | 
				
			||||||
 | 
					that is to say, a work containing the Program or a portion of it,
 | 
				
			||||||
 | 
					either verbatim or with modifications and/or translated into another
 | 
				
			||||||
 | 
					language.  (Hereinafter, translation is included without limitation in
 | 
				
			||||||
 | 
					the term "modification".)  Each licensee is addressed as "you".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Activities other than copying, distribution and modification are not
 | 
				
			||||||
 | 
					covered by this License; they are outside its scope.  The act of
 | 
				
			||||||
 | 
					running the Program is not restricted, and the output from the Program
 | 
				
			||||||
 | 
					is covered only if its contents constitute a work based on the
 | 
				
			||||||
 | 
					Program (independent of having been made by running the Program).
 | 
				
			||||||
 | 
					Whether that is true depends on what the Program does.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1. You may copy and distribute verbatim copies of the Program's
 | 
				
			||||||
 | 
					source code as you receive it, in any medium, provided that you
 | 
				
			||||||
 | 
					conspicuously and appropriately publish on each copy an appropriate
 | 
				
			||||||
 | 
					copyright notice and disclaimer of warranty; keep intact all the
 | 
				
			||||||
 | 
					notices that refer to this License and to the absence of any warranty;
 | 
				
			||||||
 | 
					and give any other recipients of the Program a copy of this License
 | 
				
			||||||
 | 
					along with the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You may charge a fee for the physical act of transferring a copy, and
 | 
				
			||||||
 | 
					you may at your option offer warranty protection in exchange for a fee.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  2. You may modify your copy or copies of the Program or any portion
 | 
				
			||||||
 | 
					of it, thus forming a work based on the Program, and copy and
 | 
				
			||||||
 | 
					distribute such modifications or work under the terms of Section 1
 | 
				
			||||||
 | 
					above, provided that you also meet all of these conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) You must cause the modified files to carry prominent notices
 | 
				
			||||||
 | 
					    stating that you changed the files and the date of any change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) You must cause any work that you distribute or publish, that in
 | 
				
			||||||
 | 
					    whole or in part contains or is derived from the Program or any
 | 
				
			||||||
 | 
					    part thereof, to be licensed as a whole at no charge to all third
 | 
				
			||||||
 | 
					    parties under the terms of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) If the modified program normally reads commands interactively
 | 
				
			||||||
 | 
					    when run, you must cause it, when started running for such
 | 
				
			||||||
 | 
					    interactive use in the most ordinary way, to print or display an
 | 
				
			||||||
 | 
					    announcement including an appropriate copyright notice and a
 | 
				
			||||||
 | 
					    notice that there is no warranty (or else, saying that you provide
 | 
				
			||||||
 | 
					    a warranty) and that users may redistribute the program under
 | 
				
			||||||
 | 
					    these conditions, and telling the user how to view a copy of this
 | 
				
			||||||
 | 
					    License.  (Exception: if the Program itself is interactive but
 | 
				
			||||||
 | 
					    does not normally print such an announcement, your work based on
 | 
				
			||||||
 | 
					    the Program is not required to print an announcement.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These requirements apply to the modified work as a whole.  If
 | 
				
			||||||
 | 
					identifiable sections of that work are not derived from the Program,
 | 
				
			||||||
 | 
					and can be reasonably considered independent and separate works in
 | 
				
			||||||
 | 
					themselves, then this License, and its terms, do not apply to those
 | 
				
			||||||
 | 
					sections when you distribute them as separate works.  But when you
 | 
				
			||||||
 | 
					distribute the same sections as part of a whole which is a work based
 | 
				
			||||||
 | 
					on the Program, the distribution of the whole must be on the terms of
 | 
				
			||||||
 | 
					this License, whose permissions for other licensees extend to the
 | 
				
			||||||
 | 
					entire whole, and thus to each and every part regardless of who wrote it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thus, it is not the intent of this section to claim rights or contest
 | 
				
			||||||
 | 
					your rights to work written entirely by you; rather, the intent is to
 | 
				
			||||||
 | 
					exercise the right to control the distribution of derivative or
 | 
				
			||||||
 | 
					collective works based on the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, mere aggregation of another work not based on the Program
 | 
				
			||||||
 | 
					with the Program (or with a work based on the Program) on a volume of
 | 
				
			||||||
 | 
					a storage or distribution medium does not bring the other work under
 | 
				
			||||||
 | 
					the scope of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  3. You may copy and distribute the Program (or a work based on it,
 | 
				
			||||||
 | 
					under Section 2) in object code or executable form under the terms of
 | 
				
			||||||
 | 
					Sections 1 and 2 above provided that you also do one of the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) Accompany it with the complete corresponding machine-readable
 | 
				
			||||||
 | 
					    source code, which must be distributed under the terms of Sections
 | 
				
			||||||
 | 
					    1 and 2 above on a medium customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) Accompany it with a written offer, valid for at least three
 | 
				
			||||||
 | 
					    years, to give any third party, for a charge no more than your
 | 
				
			||||||
 | 
					    cost of physically performing source distribution, a complete
 | 
				
			||||||
 | 
					    machine-readable copy of the corresponding source code, to be
 | 
				
			||||||
 | 
					    distributed under the terms of Sections 1 and 2 above on a medium
 | 
				
			||||||
 | 
					    customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) Accompany it with the information you received as to the offer
 | 
				
			||||||
 | 
					    to distribute corresponding source code.  (This alternative is
 | 
				
			||||||
 | 
					    allowed only for noncommercial distribution and only if you
 | 
				
			||||||
 | 
					    received the program in object code or executable form with such
 | 
				
			||||||
 | 
					    an offer, in accord with Subsection b above.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code for a work means the preferred form of the work for
 | 
				
			||||||
 | 
					making modifications to it.  For an executable work, complete source
 | 
				
			||||||
 | 
					code means all the source code for all modules it contains, plus any
 | 
				
			||||||
 | 
					associated interface definition files, plus the scripts used to
 | 
				
			||||||
 | 
					control compilation and installation of the executable.  However, as a
 | 
				
			||||||
 | 
					special exception, the source code distributed need not include
 | 
				
			||||||
 | 
					anything that is normally distributed (in either source or binary
 | 
				
			||||||
 | 
					form) with the major components (compiler, kernel, and so on) of the
 | 
				
			||||||
 | 
					operating system on which the executable runs, unless that component
 | 
				
			||||||
 | 
					itself accompanies the executable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If distribution of executable or object code is made by offering
 | 
				
			||||||
 | 
					access to copy from a designated place, then offering equivalent
 | 
				
			||||||
 | 
					access to copy the source code from the same place counts as
 | 
				
			||||||
 | 
					distribution of the source code, even though third parties are not
 | 
				
			||||||
 | 
					compelled to copy the source along with the object code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  4. You may not copy, modify, sublicense, or distribute the Program
 | 
				
			||||||
 | 
					except as expressly provided under this License.  Any attempt
 | 
				
			||||||
 | 
					otherwise to copy, modify, sublicense or distribute the Program is
 | 
				
			||||||
 | 
					void, and will automatically terminate your rights under this License.
 | 
				
			||||||
 | 
					However, parties who have received copies, or rights, from you under
 | 
				
			||||||
 | 
					this License will not have their licenses terminated so long as such
 | 
				
			||||||
 | 
					parties remain in full compliance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  5. You are not required to accept this License, since you have not
 | 
				
			||||||
 | 
					signed it.  However, nothing else grants you permission to modify or
 | 
				
			||||||
 | 
					distribute the Program or its derivative works.  These actions are
 | 
				
			||||||
 | 
					prohibited by law if you do not accept this License.  Therefore, by
 | 
				
			||||||
 | 
					modifying or distributing the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), you indicate your acceptance of this License to do so, and
 | 
				
			||||||
 | 
					all its terms and conditions for copying, distributing or modifying
 | 
				
			||||||
 | 
					the Program or works based on it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  6. Each time you redistribute the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), the recipient automatically receives a license from the
 | 
				
			||||||
 | 
					original licensor to copy, distribute or modify the Program subject to
 | 
				
			||||||
 | 
					these terms and conditions.  You may not impose any further
 | 
				
			||||||
 | 
					restrictions on the recipients' exercise of the rights granted herein.
 | 
				
			||||||
 | 
					You are not responsible for enforcing compliance by third parties to
 | 
				
			||||||
 | 
					this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  7. If, as a consequence of a court judgment or allegation of patent
 | 
				
			||||||
 | 
					infringement or for any other reason (not limited to patent issues),
 | 
				
			||||||
 | 
					conditions are imposed on you (whether by court order, agreement or
 | 
				
			||||||
 | 
					otherwise) that contradict the conditions of this License, they do not
 | 
				
			||||||
 | 
					excuse you from the conditions of this License.  If you cannot
 | 
				
			||||||
 | 
					distribute so as to satisfy simultaneously your obligations under this
 | 
				
			||||||
 | 
					License and any other pertinent obligations, then as a consequence you
 | 
				
			||||||
 | 
					may not distribute the Program at all.  For example, if a patent
 | 
				
			||||||
 | 
					license would not permit royalty-free redistribution of the Program by
 | 
				
			||||||
 | 
					all those who receive copies directly or indirectly through you, then
 | 
				
			||||||
 | 
					the only way you could satisfy both it and this License would be to
 | 
				
			||||||
 | 
					refrain entirely from distribution of the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If any portion of this section is held invalid or unenforceable under
 | 
				
			||||||
 | 
					any particular circumstance, the balance of the section is intended to
 | 
				
			||||||
 | 
					apply and the section as a whole is intended to apply in other
 | 
				
			||||||
 | 
					circumstances.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is not the purpose of this section to induce you to infringe any
 | 
				
			||||||
 | 
					patents or other property right claims or to contest validity of any
 | 
				
			||||||
 | 
					such claims; this section has the sole purpose of protecting the
 | 
				
			||||||
 | 
					integrity of the free software distribution system, which is
 | 
				
			||||||
 | 
					implemented by public license practices.  Many people have made
 | 
				
			||||||
 | 
					generous contributions to the wide range of software distributed
 | 
				
			||||||
 | 
					through that system in reliance on consistent application of that
 | 
				
			||||||
 | 
					system; it is up to the author/donor to decide if he or she is willing
 | 
				
			||||||
 | 
					to distribute software through any other system and a licensee cannot
 | 
				
			||||||
 | 
					impose that choice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section is intended to make thoroughly clear what is believed to
 | 
				
			||||||
 | 
					be a consequence of the rest of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  8. If the distribution and/or use of the Program is restricted in
 | 
				
			||||||
 | 
					certain countries either by patents or by copyrighted interfaces, the
 | 
				
			||||||
 | 
					original copyright holder who places the Program under this License
 | 
				
			||||||
 | 
					may add an explicit geographical distribution limitation excluding
 | 
				
			||||||
 | 
					those countries, so that distribution is permitted only in or among
 | 
				
			||||||
 | 
					countries not thus excluded.  In such case, this License incorporates
 | 
				
			||||||
 | 
					the limitation as if written in the body of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  9. The Free Software Foundation may publish revised and/or new versions
 | 
				
			||||||
 | 
					of the General Public License from time to time.  Such new versions will
 | 
				
			||||||
 | 
					be similar in spirit to the present version, but may differ in detail to
 | 
				
			||||||
 | 
					address new problems or concerns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each version is given a distinguishing version number.  If the Program
 | 
				
			||||||
 | 
					specifies a version number of this License which applies to it and "any
 | 
				
			||||||
 | 
					later version", you have the option of following the terms and conditions
 | 
				
			||||||
 | 
					either of that version or of any later version published by the Free
 | 
				
			||||||
 | 
					Software Foundation.  If the Program does not specify a version number of
 | 
				
			||||||
 | 
					this License, you may choose any version ever published by the Free Software
 | 
				
			||||||
 | 
					Foundation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  10. If you wish to incorporate parts of the Program into other free
 | 
				
			||||||
 | 
					programs whose distribution conditions are different, write to the author
 | 
				
			||||||
 | 
					to ask for permission.  For software which is copyrighted by the Free
 | 
				
			||||||
 | 
					Software Foundation, write to the Free Software Foundation; we sometimes
 | 
				
			||||||
 | 
					make exceptions for this.  Our decision will be guided by the two goals
 | 
				
			||||||
 | 
					of preserving the free status of all derivatives of our free software and
 | 
				
			||||||
 | 
					of promoting the sharing and reuse of software generally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            NO WARRANTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
				
			||||||
 | 
					FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
				
			||||||
 | 
					OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
				
			||||||
 | 
					PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
				
			||||||
 | 
					OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
				
			||||||
 | 
					TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
				
			||||||
 | 
					PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
				
			||||||
 | 
					REPAIR OR CORRECTION.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
				
			||||||
 | 
					WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
				
			||||||
 | 
					REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
				
			||||||
 | 
					INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
				
			||||||
 | 
					OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
				
			||||||
 | 
					TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
				
			||||||
 | 
					YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
				
			||||||
 | 
					PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
				
			||||||
 | 
					POSSIBILITY OF SUCH DAMAGES.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                     END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            How to Apply These Terms to Your New Programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  If you develop a new program, and you want it to be of the greatest
 | 
				
			||||||
 | 
					possible use to the public, the best way to achieve this is to make it
 | 
				
			||||||
 | 
					free software which everyone can redistribute and change under these terms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To do so, attach the following notices to the program.  It is safest
 | 
				
			||||||
 | 
					to attach them to the start of each source file to most effectively
 | 
				
			||||||
 | 
					convey the exclusion of warranty; and each file should have at least
 | 
				
			||||||
 | 
					the "copyright" line and a pointer to where the full notice is found.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <one line to give the program's name and a brief idea of what it does.>
 | 
				
			||||||
 | 
					    Copyright (C) <year>  <name of author>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					    the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					    (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					    GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					    along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also add information on how to contact you by electronic and paper mail.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the program is interactive, make it output a short notice like this
 | 
				
			||||||
 | 
					when it starts in an interactive mode:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Gnomovision version 69, Copyright (C) year name of author
 | 
				
			||||||
 | 
					    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
				
			||||||
 | 
					    This is free software, and you are welcome to redistribute it
 | 
				
			||||||
 | 
					    under certain conditions; type `show c' for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The hypothetical commands `show w' and `show c' should show the appropriate
 | 
				
			||||||
 | 
					parts of the General Public License.  Of course, the commands you use may
 | 
				
			||||||
 | 
					be called something other than `show w' and `show c'; they could even be
 | 
				
			||||||
 | 
					mouse-clicks or menu items--whatever suits your program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should also get your employer (if you work as a programmer) or your
 | 
				
			||||||
 | 
					school, if any, to sign a "copyright disclaimer" for the program, if
 | 
				
			||||||
 | 
					necessary.  Here is a sample; alter the names:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 | 
				
			||||||
 | 
					  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <signature of Ty Coon>, 1 April 1989
 | 
				
			||||||
 | 
					  Ty Coon, President of Vice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This General Public License does not permit incorporating your program into
 | 
				
			||||||
 | 
					proprietary programs.  If your program is a subroutine library, you may
 | 
				
			||||||
 | 
					consider it more useful to permit linking proprietary applications with the
 | 
				
			||||||
 | 
					library.  If this is what you want to do, use the GNU Library General
 | 
				
			||||||
 | 
					Public License instead of this License.
 | 
				
			||||||
							
								
								
									
										88
									
								
								firmware/usbdrv/Readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								firmware/usbdrv/Readme.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					This is the Readme file to Objective Development's firmware-only USB driver
 | 
				
			||||||
 | 
					for Atmel AVR microcontrollers. For more information please visit
 | 
				
			||||||
 | 
					http://www.obdev.at/avrusb/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This directory contains the USB firmware only. Copy it as-is to your own
 | 
				
			||||||
 | 
					project and add your own version of "usbconfig.h". A template for your own
 | 
				
			||||||
 | 
					"usbconfig.h" can be found in "usbconfig-prototype.h" in this directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TECHNICAL DOCUMENTATION
 | 
				
			||||||
 | 
					=======================
 | 
				
			||||||
 | 
					The technical documentation for the firmware driver is contained in the file
 | 
				
			||||||
 | 
					"usbdrv.h". Please read all of it carefully!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USB IDENTIFIERS
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs
 | 
				
			||||||
 | 
					are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you
 | 
				
			||||||
 | 
					can assign PIDs at will.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Since an entry level cost of 1,500 USD is too high for most small companies
 | 
				
			||||||
 | 
					and hobbyists, we provide a single VID/PID pair for free. If you want to use
 | 
				
			||||||
 | 
					your own VID and PID instead of our's, define the macros "USB_CFG_VENDOR_ID"
 | 
				
			||||||
 | 
					and "USB_CFG_DEVICE_ID" accordingly in "usbconfig.h".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To use our predefined VID/PID pair, you MUST conform to a couple of
 | 
				
			||||||
 | 
					requirements. See the file "USBID-License.txt" for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HOST DRIVER
 | 
				
			||||||
 | 
					===========
 | 
				
			||||||
 | 
					You have received this driver together with an example device implementation
 | 
				
			||||||
 | 
					and an example host driver. The host driver is based on libusb and compiles
 | 
				
			||||||
 | 
					on various Unix flavors (Linux, BSD, Mac OS X). It also compiles natively on
 | 
				
			||||||
 | 
					Windows using MinGW (see www.mingw.org) and libusb-win32 (see
 | 
				
			||||||
 | 
					libusb-win32.sourceforge.net). The "Automator" project contains a native
 | 
				
			||||||
 | 
					Windows host driver (not based on libusb) for Human Interface Devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEVELOPMENT SYSTEM
 | 
				
			||||||
 | 
					==================
 | 
				
			||||||
 | 
					This driver has been developed and optimized for the GNU compiler version 3
 | 
				
			||||||
 | 
					(gcc 3). It does work well with gcc 4 and future versions will probably be
 | 
				
			||||||
 | 
					optimized for gcc 4. We recommend that you use the GNU compiler suite because
 | 
				
			||||||
 | 
					it is freely available. AVR-USB has also been ported to the IAR compiler and
 | 
				
			||||||
 | 
					assembler. It has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8
 | 
				
			||||||
 | 
					with the "small" and "tiny" memory model. Please note that gcc is more
 | 
				
			||||||
 | 
					efficient for usbdrv.c because this module has been deliberately optimized
 | 
				
			||||||
 | 
					for gcc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USING AVR-USB FOR FREE
 | 
				
			||||||
 | 
					======================
 | 
				
			||||||
 | 
					The AVR firmware driver is published under an Open Source compliant license.
 | 
				
			||||||
 | 
					See the file "License.txt" for details. Since it is not obvious for many
 | 
				
			||||||
 | 
					people how this license applies to their own projects, here's a short guide:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(1) The USB driver and all your modifications to the driver itself are owned
 | 
				
			||||||
 | 
					by Objective Development. You must give us a worldwide, perpetual,
 | 
				
			||||||
 | 
					irrevocable royalty free license for your modifications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(2) Since you own the code you have written (except where you modify our
 | 
				
			||||||
 | 
					driver), you can (at least in principle) determine the license for it freely.
 | 
				
			||||||
 | 
					However, to "pay" for the USB driver code you link against, we demand that
 | 
				
			||||||
 | 
					you choose an Open Source compliant license (compatible with our license) for
 | 
				
			||||||
 | 
					your source code and the hardware circuit diagrams. Simply attach your
 | 
				
			||||||
 | 
					license of choice to your parts of the project and leave our "License.txt" in
 | 
				
			||||||
 | 
					the "usbdrv" subdirectory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(3) We also demand that you publish your work on the Internet and drop us a
 | 
				
			||||||
 | 
					note with the URL. The publication must meet certain formal criteria (files
 | 
				
			||||||
 | 
					distributed, file formats etc.). See the file "License.txt" for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Other than that, you are allowed to manufacture any number of units and sell
 | 
				
			||||||
 | 
					them for any price. If you like our driver, we also encourage you to make a
 | 
				
			||||||
 | 
					donation on our web site.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMERCIAL LICENSES FOR AVR-USB
 | 
				
			||||||
 | 
					===============================
 | 
				
			||||||
 | 
					If you don't want to publish your source code and the circuit diagrams under
 | 
				
			||||||
 | 
					an Open Source license, you can simply pay money for AVR-USB. As an
 | 
				
			||||||
 | 
					additional benefit you get USB PIDs for free, licensed exclusively to you.
 | 
				
			||||||
 | 
					See http://www.obdev.at/products/avrusb/license.html for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										143
									
								
								firmware/usbdrv/USBID-License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								firmware/usbdrv/USBID-License.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					Royalty-Free Non-Exclusive License USB Product-ID
 | 
				
			||||||
 | 
					=================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Version 2006-06-19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive
 | 
				
			||||||
 | 
					right to use three USB.org vendor-ID (VID) / product-ID (PID) pairs with
 | 
				
			||||||
 | 
					products based on Objective Development's firmware-only USB driver for
 | 
				
			||||||
 | 
					Atmel AVR microcontrollers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * VID = 5824 (=0x16c0) / PID = 1500 (=0x5dc) for devices implementing no
 | 
				
			||||||
 | 
					   USB device class (vendor-class devices with USB class = 0xff). Devices
 | 
				
			||||||
 | 
					   using this pair will be referred to as "VENDOR CLASS" devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * VID = 5824 (=0x16c0) / PID = 1503 (=0x5df) for HID class devices
 | 
				
			||||||
 | 
					   (excluding mice and keyboards). Devices using this pair will be referred
 | 
				
			||||||
 | 
					   to as "HID CLASS" devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * VID = 5824 (=0x16c0) / PID = 1505 (=0x5e1) for CDC class modem devices
 | 
				
			||||||
 | 
					   Devices using this pair will be referred to as "CDC-ACM CLASS" devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Since the granted right is non-exclusive, the same VID/PID pairs may be
 | 
				
			||||||
 | 
					used by many companies and individuals for different products. To avoid
 | 
				
			||||||
 | 
					conflicts, your device and host driver software MUST adhere to the rules
 | 
				
			||||||
 | 
					outlined below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJECTIVE DEVELOPMENT Software GmbH has licensed these VID/PID pairs from
 | 
				
			||||||
 | 
					Wouter van Ooijen (see www.voti.nl), who has licensed the VID from the USB
 | 
				
			||||||
 | 
					Implementers Forum, Inc. (see www.usb.org). The VID is registered for the
 | 
				
			||||||
 | 
					company name "Van Ooijen Technische Informatica".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RULES AND RESTRICTIONS
 | 
				
			||||||
 | 
					======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(1) The USB device MUST provide a textual representation of the
 | 
				
			||||||
 | 
					manufacturer and product identification. The manufacturer identification
 | 
				
			||||||
 | 
					MUST be available at least in USB language 0x0409 (English/US).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(2) The textual manufacturer identification MUST contain either an Internet
 | 
				
			||||||
 | 
					domain name (e.g. "mycompany.com") registered and owned by you, or an
 | 
				
			||||||
 | 
					e-mail address under your control (e.g. "myname@gmx.net"). You can embed
 | 
				
			||||||
 | 
					the domain name or e-mail address in any string you like, e.g.  "Objective
 | 
				
			||||||
 | 
					Development http://www.obdev.at/avrusb/".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(3) You are responsible for retaining ownership of the domain or e-mail
 | 
				
			||||||
 | 
					address for as long as any of your products are in use.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(4) You may choose any string for the textual product identification, as
 | 
				
			||||||
 | 
					long as this string is unique within the scope of your textual manufacturer
 | 
				
			||||||
 | 
					identification.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(5) Matching of device-specific drivers MUST be based on the textual
 | 
				
			||||||
 | 
					manufacturer and product identification in addition to the usual VID/PID
 | 
				
			||||||
 | 
					matching. This means that operating system features which are based on
 | 
				
			||||||
 | 
					VID/PID matching only (e.g. Windows kernel level drivers, automatic actions
 | 
				
			||||||
 | 
					when the device is plugged in etc) MUST NOT be used. The driver matching
 | 
				
			||||||
 | 
					MUST be a comparison of the entire strings, NOT a sub-string match. For
 | 
				
			||||||
 | 
					CDC-ACM CLASS devices, a generic class driver should be used and the
 | 
				
			||||||
 | 
					matching is based on the USB device class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(6) The extent to which VID/PID matching is allowed for non device-specific
 | 
				
			||||||
 | 
					drivers or features depends on the operating system and particular VID/PID
 | 
				
			||||||
 | 
					pair used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Mac OS X, Linux, FreeBSD and other Unixes: No VID/PID matching is
 | 
				
			||||||
 | 
					   required and hence no VID/PID-only matching is allowed at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Windows: The operating system performs VID/PID matching for the kernel
 | 
				
			||||||
 | 
					   level driver. You are REQUIRED to use libusb-win32 (see
 | 
				
			||||||
 | 
					   http://libusb-win32.sourceforge.net/) as the kernel level driver for
 | 
				
			||||||
 | 
					   VENDOR CLASS devices. HID CLASS devices all use the generic HID class
 | 
				
			||||||
 | 
					   driver shipped with Windows, except mice and keyboards. You therefore
 | 
				
			||||||
 | 
					   MUST NOT use any of the shared VID/PID pairs for mice or keyboards.
 | 
				
			||||||
 | 
					   CDC-ACM CLASS devices require a ".inf" file which matches on the VID/PID
 | 
				
			||||||
 | 
					   pair. This ".inf" file MUST load the "usbser" driver to configure the
 | 
				
			||||||
 | 
					   device as modem (COM-port).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any
 | 
				
			||||||
 | 
					problems which are caused by the shared use of these VID/PID pairs. You
 | 
				
			||||||
 | 
					have been warned that the sharing of VID/PID pairs may cause problems. If
 | 
				
			||||||
 | 
					you want to avoid them, get your own VID/PID pair for exclusive use.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HOW TO IMPLEMENT THESE RULES
 | 
				
			||||||
 | 
					============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following rules are for VENDOR CLASS and HID CLASS devices. CDC-ACM
 | 
				
			||||||
 | 
					CLASS devices use the operating system's class driver and don't need a
 | 
				
			||||||
 | 
					custom driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The host driver MUST iterate over all devices with the given VID/PID
 | 
				
			||||||
 | 
					numbers in their device descriptors and query the string representation for
 | 
				
			||||||
 | 
					the manufacturer name in USB language 0x0409 (English/US). It MUST compare
 | 
				
			||||||
 | 
					the ENTIRE string with your textual manufacturer identification chosen in
 | 
				
			||||||
 | 
					(2) above. A substring search for your domain or e-mail address is NOT
 | 
				
			||||||
 | 
					acceptable. The driver MUST NOT touch the device (other than querying the
 | 
				
			||||||
 | 
					descriptors) unless the strings match.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For all USB devices with matching VID/PID and textual manufacturer
 | 
				
			||||||
 | 
					identification, the host driver must query the textual product
 | 
				
			||||||
 | 
					identification and string-compare it with the name of the product it can
 | 
				
			||||||
 | 
					control. It may only initialize the device if the product matches exactly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Objective Development provides examples for these matching rules with the
 | 
				
			||||||
 | 
					"PowerSwitch" project (using libusb) and with the "Automator" project
 | 
				
			||||||
 | 
					(using Windows calls on Windows and libusb on Unix).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Technical Notes:
 | 
				
			||||||
 | 
					================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sharing the same VID/PID pair among devices is possible as long as ALL
 | 
				
			||||||
 | 
					drivers which match the VID/PID also perform matching on the textual
 | 
				
			||||||
 | 
					identification strings. This is easy on all operating systems except
 | 
				
			||||||
 | 
					Windows, since Windows establishes a static connection between the VID/PID
 | 
				
			||||||
 | 
					pair and a kernel level driver. All devices with the same VID/PID pair must
 | 
				
			||||||
 | 
					therefore use THE SAME kernel level driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We therefore demand that you use libusb-win32 for VENDOR CLASS devices.
 | 
				
			||||||
 | 
					This is a generic kernel level driver which allows all types of USB access
 | 
				
			||||||
 | 
					for user space applications. This is only a partial solution of the
 | 
				
			||||||
 | 
					problem, though, because different device drivers may come with different
 | 
				
			||||||
 | 
					versions of libusb-win32 and they may not work with the libusb version of
 | 
				
			||||||
 | 
					the respective other driver. You are therefore encouraged to test your
 | 
				
			||||||
 | 
					driver against a broad range of libusb-win32 versions. Do not use new
 | 
				
			||||||
 | 
					features in new versions, or check for their existence before you use them.
 | 
				
			||||||
 | 
					When a new libusb-win32 becomes available, make sure that your driver is
 | 
				
			||||||
 | 
					compatible with it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For HID CLASS devices it is necessary that all those devices bind to the
 | 
				
			||||||
 | 
					same kernel driver: Microsoft's generic USB HID driver. This is true for
 | 
				
			||||||
 | 
					all HID devices except those with a specialized driver. Currently, the only
 | 
				
			||||||
 | 
					HIDs with specialized drivers are mice and keyboards. You therefore MUST
 | 
				
			||||||
 | 
					NOT use a shared VID/PID with mouse and keyboard devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sharing the same VID/PID among different products is unusual and probably
 | 
				
			||||||
 | 
					violates the USB specification. If you do it, you do it at your own risk.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To avoid possible incompatibilities, we highly recommend that you get your
 | 
				
			||||||
 | 
					own VID/PID pair if you intend to sell your product. Objective
 | 
				
			||||||
 | 
					Development's commercial licenses for AVR-USB include a PID for
 | 
				
			||||||
 | 
					unrestricted exclusive use.
 | 
				
			||||||
							
								
								
									
										70
									
								
								firmware/usbdrv/iarcompat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								firmware/usbdrv/iarcompat.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					/* Name: iarcompat.h
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2006-03-01
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: iarcompat.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					This header is included when we compile with the IAR C-compiler and assembler.
 | 
				
			||||||
 | 
					It defines macros for cross compatibility between gcc and IAR-cc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thanks to Oleg Semyonov for his help with the IAR tools port!
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __iarcompat_h_INCLUDED__
 | 
				
			||||||
 | 
					#define __iarcompat_h_INCLUDED__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Enable bit definitions */
 | 
				
			||||||
 | 
					#ifndef ENABLE_BIT_DEFINITIONS
 | 
				
			||||||
 | 
					#   define ENABLE_BIT_DEFINITIONS	1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Include IAR headers */
 | 
				
			||||||
 | 
					#include <ioavr.h>
 | 
				
			||||||
 | 
					#ifndef __IAR_SYSTEMS_ASM__
 | 
				
			||||||
 | 
					#   include <inavr.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __attribute__(arg)
 | 
				
			||||||
 | 
					#define IAR_SECTION(section)    @ section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_BUFFER_SECTION
 | 
				
			||||||
 | 
					#   define  USB_BUFFER_SECTION  "TINY_Z"    /* if user has not selected a named section */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __IAR_SYSTEMS_ASM__
 | 
				
			||||||
 | 
					#   define __ASSEMBLER__
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __HAS_ELPM__
 | 
				
			||||||
 | 
					#   define PROGMEM __farflash
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#   define PROGMEM __flash
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PRG_RDB(addr)   (*(PROGMEM char *)(addr))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The following definitions are not needed by the driver, but may be of some
 | 
				
			||||||
 | 
					 * help if you port a gcc based project to IAR.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define cli()       __disable_interrupt()
 | 
				
			||||||
 | 
					#define sei()       __enable_interrupt()
 | 
				
			||||||
 | 
					#define wdt_reset() __watchdog_reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Depending on the device you use, you may get problems with the way usbdrv.h
 | 
				
			||||||
 | 
					 * handles the differences between devices. Since IAR does not use #defines
 | 
				
			||||||
 | 
					 * for MCU registers, we can't check for the existence of a particular
 | 
				
			||||||
 | 
					 * register with an #ifdef. If the autodetection mechanism fails, include
 | 
				
			||||||
 | 
					 * definitions for the required USB_INTR_* macros in your usbconfig.h. See
 | 
				
			||||||
 | 
					 * usbconfig-prototype.h and usbdrv.h for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */
 | 
				
			||||||
 | 
					#endif  /* __iarcompat_h_INCLUDED__ */
 | 
				
			||||||
							
								
								
									
										53
									
								
								firmware/usbdrv/oddebug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								firmware/usbdrv/oddebug.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					/* Name: oddebug.c
 | 
				
			||||||
 | 
					 * Project: AVR library
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2005-01-16
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: oddebug.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "oddebug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG_LEVEL > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uchar Warning__Never_compile_production_devices_with_debugging;
 | 
				
			||||||
 | 
					/* The "#warning" preprocessor directive is non-standard. The unused static
 | 
				
			||||||
 | 
					 * variable above should give a compiler warning on all compilers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void uartPutc(char c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    while(!(ODDBG_USR & (1 << ODDBG_UDRE)));    /* wait for data register empty */
 | 
				
			||||||
 | 
					    ODDBG_UDR = c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uchar    hexAscii(uchar h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    h &= 0xf;
 | 
				
			||||||
 | 
					    if(h >= 10)
 | 
				
			||||||
 | 
					        h += 'a' - (uchar)10 - '0';
 | 
				
			||||||
 | 
					    h += '0';
 | 
				
			||||||
 | 
					    return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void printHex(uchar c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uartPutc(hexAscii(c >> 4));
 | 
				
			||||||
 | 
					    uartPutc(hexAscii(c));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void    odDebug(uchar prefix, uchar *data, uchar len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    printHex(prefix);
 | 
				
			||||||
 | 
					    uartPutc(':');
 | 
				
			||||||
 | 
					    while(len--){
 | 
				
			||||||
 | 
					        uartPutc(' ');
 | 
				
			||||||
 | 
					        printHex(*data++);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    uartPutc('\r');
 | 
				
			||||||
 | 
					    uartPutc('\n');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										126
									
								
								firmware/usbdrv/oddebug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								firmware/usbdrv/oddebug.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					/* Name: oddebug.h
 | 
				
			||||||
 | 
					 * Project: AVR library
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2005-01-16
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: oddebug.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __oddebug_h_included__
 | 
				
			||||||
 | 
					#define __oddebug_h_included__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					This module implements a function for debug logs on the serial line of the
 | 
				
			||||||
 | 
					AVR microcontroller. Debugging can be configured with the define
 | 
				
			||||||
 | 
					'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging
 | 
				
			||||||
 | 
					calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is
 | 
				
			||||||
 | 
					2, DBG1 and DBG2 logs will be printed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A debug log consists of a label ('prefix') to indicate which debug log created
 | 
				
			||||||
 | 
					the output and a memory block to dump in hex ('data' and 'len').
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef F_CPU
 | 
				
			||||||
 | 
					#   define  F_CPU   12000000    /* 12 MHz */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* make sure we have the UART defines: */
 | 
				
			||||||
 | 
					#include "iarcompat.h"
 | 
				
			||||||
 | 
					#ifndef __IAR_SYSTEMS_ICC__
 | 
				
			||||||
 | 
					#   include <avr/io.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef uchar
 | 
				
			||||||
 | 
					#   define  uchar   unsigned char
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */
 | 
				
			||||||
 | 
					#   warning "Debugging disabled because device has no UART"
 | 
				
			||||||
 | 
					#   undef   DEBUG_LEVEL
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef DEBUG_LEVEL
 | 
				
			||||||
 | 
					#   define  DEBUG_LEVEL 0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG_LEVEL > 0
 | 
				
			||||||
 | 
					#   define  DBG1(prefix, data, len) odDebug(prefix, data, len)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#   define  DBG1(prefix, data, len)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG_LEVEL > 1
 | 
				
			||||||
 | 
					#   define  DBG2(prefix, data, len) odDebug(prefix, data, len)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#   define  DBG2(prefix, data, len)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG_LEVEL > 0
 | 
				
			||||||
 | 
					extern void odDebug(uchar prefix, uchar *data, uchar len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Try to find our control registers; ATMEL likes to rename these */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined UBRR
 | 
				
			||||||
 | 
					#   define  ODDBG_UBRR  UBRR
 | 
				
			||||||
 | 
					#elif defined UBRRL
 | 
				
			||||||
 | 
					#   define  ODDBG_UBRR  UBRRL
 | 
				
			||||||
 | 
					#elif defined UBRR0
 | 
				
			||||||
 | 
					#   define  ODDBG_UBRR  UBRR0
 | 
				
			||||||
 | 
					#elif defined UBRR0L
 | 
				
			||||||
 | 
					#   define  ODDBG_UBRR  UBRR0L
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined UCR
 | 
				
			||||||
 | 
					#   define  ODDBG_UCR   UCR
 | 
				
			||||||
 | 
					#elif defined UCSRB
 | 
				
			||||||
 | 
					#   define  ODDBG_UCR   UCSRB
 | 
				
			||||||
 | 
					#elif defined UCSR0B
 | 
				
			||||||
 | 
					#   define  ODDBG_UCR   UCSR0B
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined TXEN
 | 
				
			||||||
 | 
					#   define  ODDBG_TXEN  TXEN
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#   define  ODDBG_TXEN  TXEN0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined USR
 | 
				
			||||||
 | 
					#   define  ODDBG_USR   USR
 | 
				
			||||||
 | 
					#elif defined UCSRA
 | 
				
			||||||
 | 
					#   define  ODDBG_USR   UCSRA
 | 
				
			||||||
 | 
					#elif defined UCSR0A
 | 
				
			||||||
 | 
					#   define  ODDBG_USR   UCSR0A
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined UDRE
 | 
				
			||||||
 | 
					#   define  ODDBG_UDRE  UDRE
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#   define  ODDBG_UDRE  UDRE0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined UDR
 | 
				
			||||||
 | 
					#   define  ODDBG_UDR   UDR
 | 
				
			||||||
 | 
					#elif defined UDR0
 | 
				
			||||||
 | 
					#   define  ODDBG_UDR   UDR0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void  odDebugInit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ODDBG_UCR |= (1<<ODDBG_TXEN);
 | 
				
			||||||
 | 
					    ODDBG_UBRR = F_CPU / (19200 * 16L) - 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#   define odDebugInit()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __oddebug_h_included__ */
 | 
				
			||||||
							
								
								
									
										265
									
								
								firmware/usbdrv/usbconfig-prototype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								firmware/usbdrv/usbconfig-prototype.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,265 @@
 | 
				
			|||||||
 | 
					/* Name: usbconfig.h
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2005-04-01
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: usbconfig-prototype.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __usbconfig_h_included__
 | 
				
			||||||
 | 
					#define __usbconfig_h_included__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					This file is an example configuration (with inline documentation) for the USB
 | 
				
			||||||
 | 
					driver. It configures AVR-USB for an ATMega8 with USB D+ connected to Port D
 | 
				
			||||||
 | 
					bit 2 (which is also hardware interrupt 0) and USB D- to Port D bit 0. You may
 | 
				
			||||||
 | 
					wire the lines to any other port, as long as D- is on bit 0 and D+ is also
 | 
				
			||||||
 | 
					wired to INT0.
 | 
				
			||||||
 | 
					To create your own usbconfig.h file, copy this file to the directory
 | 
				
			||||||
 | 
					containing "usbdrv" (that is your project firmware source directory) and
 | 
				
			||||||
 | 
					rename it to "usbconfig.h". Then edit it accordingly.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ---------------------------- Hardware Config ---------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_CFG_IOPORTNAME      D
 | 
				
			||||||
 | 
					/* This is the port where the USB bus is connected. When you configure it to
 | 
				
			||||||
 | 
					 * "B", the registers PORTB, PINB and DDRB will be used.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DMINUS_BIT      0
 | 
				
			||||||
 | 
					/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 | 
				
			||||||
 | 
					 * This may be any bit in the port.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DPLUS_BIT       2
 | 
				
			||||||
 | 
					/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 | 
				
			||||||
 | 
					 * This may be any bit in the port. Please note that D+ must also be connected
 | 
				
			||||||
 | 
					 * to interrupt pin INT0!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ----------------------- Optional Hardware Config ------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* #define USB_CFG_PULLUP_IOPORTNAME   D */
 | 
				
			||||||
 | 
					/* If you connect the 1.5k pullup resistor from D- to a port pin instead of
 | 
				
			||||||
 | 
					 * V+, you can connect and disconnect the device from firmware by calling
 | 
				
			||||||
 | 
					 * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h).
 | 
				
			||||||
 | 
					 * This constant defines the port on which the pullup resistor is connected.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define USB_CFG_PULLUP_BIT          4 */
 | 
				
			||||||
 | 
					/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
 | 
				
			||||||
 | 
					 * above) where the 1.5k pullup resistor is connected. See description
 | 
				
			||||||
 | 
					 * above for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define  USB_BUFFER_SECTION         ".bss" */
 | 
				
			||||||
 | 
					/* The USB receive buffer (variable "usbRxBuf") with a length of 22 bytes
 | 
				
			||||||
 | 
					 * MUST NOT cross a 256 byte boundary. We have introduced this configuration
 | 
				
			||||||
 | 
					 * option to allow you to change the data segment where this buffer is
 | 
				
			||||||
 | 
					 * allocated. If you have problems with the default segment (start of .bss),
 | 
				
			||||||
 | 
					 * you may change this setting. See the comment in usbdrv.h for details.
 | 
				
			||||||
 | 
					 * On IAR C, the default is the TINY_Z segment (first 256 bytes). You must
 | 
				
			||||||
 | 
					 * change this default for devices which don't have RAM below 0x100.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* --------------------------- Functional Range ---------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_CFG_HAVE_INTRIN_ENDPOINT    1
 | 
				
			||||||
 | 
					/* Define this to 1 if you want to compile a version with two endpoints: The
 | 
				
			||||||
 | 
					 * default control endpoint 0 and an interrupt-in endpoint 1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_HAVE_INTRIN_ENDPOINT3   0
 | 
				
			||||||
 | 
					/* Define this to 1 if you want to compile a version with three endpoints: The
 | 
				
			||||||
 | 
					 * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in
 | 
				
			||||||
 | 
					 * endpoint 3. You must also enable endpoint 1 above.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_HALT          0
 | 
				
			||||||
 | 
					/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
 | 
				
			||||||
 | 
					 * for endpoint 1 (interrupt endpoint). Although you may not need this feature,
 | 
				
			||||||
 | 
					 * it is required by the standard. We have made it a config option because it
 | 
				
			||||||
 | 
					 * bloats the code considerably.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_INTR_POLL_INTERVAL      20
 | 
				
			||||||
 | 
					/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
 | 
				
			||||||
 | 
					 * interval. The value is in milliseconds and must not be less than 10 ms for
 | 
				
			||||||
 | 
					 * low speed devices.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IS_SELF_POWERED         0
 | 
				
			||||||
 | 
					/* Define this to 1 if the device has its own power supply. Set it to 0 if the
 | 
				
			||||||
 | 
					 * device is powered from the USB bus.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_MAX_BUS_POWER           100
 | 
				
			||||||
 | 
					/* Set this variable to the maximum USB bus power consumption of your device.
 | 
				
			||||||
 | 
					 * The value is in milliamperes. [It will be divided by two since USB
 | 
				
			||||||
 | 
					 * communicates power requirements in units of 2 mA.]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_SAMPLE_EXACT            1
 | 
				
			||||||
 | 
					/* This variable affects Sampling Jitter for USB receiving. When it is 0, the
 | 
				
			||||||
 | 
					 * driver guarantees a sampling window of 1/2 bit. The USB spec requires
 | 
				
			||||||
 | 
					 * that the receiver has at most 1/4 bit sampling window. The 1/2 bit window
 | 
				
			||||||
 | 
					 * should still work reliably enough because we work at low speed. If you want
 | 
				
			||||||
 | 
					 * to meet the spec, set this value to 1. This will unroll a loop which
 | 
				
			||||||
 | 
					 * results in bigger code size.
 | 
				
			||||||
 | 
					 * If you have problems with long cables, try setting this value to 1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_FN_WRITE      0
 | 
				
			||||||
 | 
					/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
 | 
				
			||||||
 | 
					 * transfers. Set it to 0 if you don't need it and want to save a couple of
 | 
				
			||||||
 | 
					 * bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_FN_READ       0
 | 
				
			||||||
 | 
					/* Set this to 1 if you need to send control replies which are generated
 | 
				
			||||||
 | 
					 * "on the fly" when usbFunctionRead() is called. If you only want to send
 | 
				
			||||||
 | 
					 * data from a static buffer, set it to 0 and return the data from
 | 
				
			||||||
 | 
					 * usbFunctionSetup(). This saves a couple of bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_IMPLEMENT_FN_WRITEOUT   0
 | 
				
			||||||
 | 
					/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoint 1.
 | 
				
			||||||
 | 
					 * You must implement the function usbFunctionWriteOut() which receives all
 | 
				
			||||||
 | 
					 * interrupt/bulk data sent to endpoint 1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_HAVE_FLOWCONTROL        0
 | 
				
			||||||
 | 
					/* Define this to 1 if you want flowcontrol over USB data. See the definition
 | 
				
			||||||
 | 
					 * of the macros usbDisableAllRequests() and usbEnableAllRequests() in
 | 
				
			||||||
 | 
					 * usbdrv.h.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* -------------------------- Device Description --------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define  USB_CFG_VENDOR_ID       0xc0, 0x16
 | 
				
			||||||
 | 
					/* USB vendor ID for the device, low byte first. If you have registered your
 | 
				
			||||||
 | 
					 * own Vendor ID, define it here. Otherwise you use obdev's free shared
 | 
				
			||||||
 | 
					 * VID/PID pair. Be sure to read USBID-License.txt for rules!
 | 
				
			||||||
 | 
					 * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df.
 | 
				
			||||||
 | 
					 * Use this VID/PID pair ONLY if you understand the implications!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define  USB_CFG_DEVICE_ID       0xdf, 0x05
 | 
				
			||||||
 | 
					/* This is the ID of the product, low byte first. It is interpreted in the
 | 
				
			||||||
 | 
					 * scope of the vendor ID. If you have registered your own VID with usb.org
 | 
				
			||||||
 | 
					 * or if you have licensed a PID from somebody else, define it here. Otherwise
 | 
				
			||||||
 | 
					 * you use obdev's free shared VID/PID pair. Be sure to read the rules in
 | 
				
			||||||
 | 
					 * USBID-License.txt!
 | 
				
			||||||
 | 
					 * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df.
 | 
				
			||||||
 | 
					 * Use this VID/PID pair ONLY if you understand the implications!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_VERSION  0x00, 0x01
 | 
				
			||||||
 | 
					/* Version number of the device: Minor number first, then major number.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_VENDOR_NAME     'w', 'w', 'w', '.', 'o', 'b', 'd', 'e', 'v', '.', 'a', 't'
 | 
				
			||||||
 | 
					#define USB_CFG_VENDOR_NAME_LEN 12
 | 
				
			||||||
 | 
					/* These two values define the vendor name returned by the USB device. The name
 | 
				
			||||||
 | 
					 * must be given as a list of characters under single quotes. The characters
 | 
				
			||||||
 | 
					 * are interpreted as Unicode (UTF-16) entities.
 | 
				
			||||||
 | 
					 * If you don't want a vendor name string, undefine these macros.
 | 
				
			||||||
 | 
					 * ALWAYS define a vendor name containing your Internet domain name if you use
 | 
				
			||||||
 | 
					 * obdev's free shared VID/PID pair. See the file USBID-License.txt for
 | 
				
			||||||
 | 
					 * details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_NAME     'T', 'e', 'm', 'p', 'l', 'a', 't', 'e'
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_NAME_LEN 8
 | 
				
			||||||
 | 
					/* Same as above for the device name. If you don't want a device name, undefine
 | 
				
			||||||
 | 
					 * the macros. See the file USBID-License.txt before you assign a name if you
 | 
				
			||||||
 | 
					 * use a shared VID/PID.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */
 | 
				
			||||||
 | 
					/*#define USB_CFG_SERIAL_NUMBER_LEN   0 */
 | 
				
			||||||
 | 
					/* Same as above for the serial number. If you don't want a serial number,
 | 
				
			||||||
 | 
					 * undefine the macros.
 | 
				
			||||||
 | 
					 * It may be useful to provide the serial number through other means than at
 | 
				
			||||||
 | 
					 * compile time. See the section about descriptor properties below for how
 | 
				
			||||||
 | 
					 * to fine tune control over USB descriptors such as the string descriptor
 | 
				
			||||||
 | 
					 * for the serial number.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_CLASS        0
 | 
				
			||||||
 | 
					#define USB_CFG_DEVICE_SUBCLASS     0
 | 
				
			||||||
 | 
					/* See USB specification if you want to conform to an existing device class.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_INTERFACE_CLASS     3   /* HID */
 | 
				
			||||||
 | 
					#define USB_CFG_INTERFACE_SUBCLASS  0
 | 
				
			||||||
 | 
					#define USB_CFG_INTERFACE_PROTOCOL  0
 | 
				
			||||||
 | 
					/* See USB specification if you want to conform to an existing device class or
 | 
				
			||||||
 | 
					 * protocol.
 | 
				
			||||||
 | 
					 * This template defines a HID class device. If you implement a vendor class
 | 
				
			||||||
 | 
					 * device, set USB_CFG_INTERFACE_CLASS to 0 and USB_CFG_DEVICE_CLASS to 0xff.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    42  /* total length of report descriptor */
 | 
				
			||||||
 | 
					/* Define this to the length of the HID report descriptor, if you implement
 | 
				
			||||||
 | 
					 * an HID device. Otherwise don't define it or define it to 0.
 | 
				
			||||||
 | 
					 * Since this template defines a HID device, it must also specify a HID
 | 
				
			||||||
 | 
					 * report descriptor length. You must add a PROGMEM character array named
 | 
				
			||||||
 | 
					 * "usbHidReportDescriptor" to your code which contains the report descriptor.
 | 
				
			||||||
 | 
					 * Don't forget to keep the array and this define in sync!
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------- Fine Control over USB Descriptors ------------------- */
 | 
				
			||||||
 | 
					/* If you don't want to use the driver's default USB descriptors, you can
 | 
				
			||||||
 | 
					 * provide our own. These can be provided as (1) fixed length static data in
 | 
				
			||||||
 | 
					 * flash memory, (2) fixed length static data in RAM or (3) dynamically at
 | 
				
			||||||
 | 
					 * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more
 | 
				
			||||||
 | 
					 * information about this function.
 | 
				
			||||||
 | 
					 * Descriptor handling is configured through the descriptor's properties. If
 | 
				
			||||||
 | 
					 * no properties are defined or if they are 0, the default descriptor is used.
 | 
				
			||||||
 | 
					 * Possible properties are:
 | 
				
			||||||
 | 
					 *   + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched
 | 
				
			||||||
 | 
					 *     at runtime via usbFunctionDescriptor().
 | 
				
			||||||
 | 
					 *   + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found
 | 
				
			||||||
 | 
					 *     in static memory is in RAM, not in flash memory.
 | 
				
			||||||
 | 
					 *   + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash),
 | 
				
			||||||
 | 
					 *     the driver must know the descriptor's length. The descriptor itself is
 | 
				
			||||||
 | 
					 *     found at the address of a well known identifier (see below).
 | 
				
			||||||
 | 
					 * List of static descriptor names (must be declared PROGMEM if in flash):
 | 
				
			||||||
 | 
					 *   char usbDescriptorDevice[];
 | 
				
			||||||
 | 
					 *   char usbDescriptorConfiguration[];
 | 
				
			||||||
 | 
					 *   char usbDescriptorHidReport[];
 | 
				
			||||||
 | 
					 *   char usbDescriptorString0[];
 | 
				
			||||||
 | 
					 *   int usbDescriptorStringVendor[];
 | 
				
			||||||
 | 
					 *   int usbDescriptorStringDevice[];
 | 
				
			||||||
 | 
					 *   int usbDescriptorStringSerialNumber[];
 | 
				
			||||||
 | 
					 * Other descriptors can't be provided statically, they must be provided
 | 
				
			||||||
 | 
					 * dynamically at runtime.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Descriptor properties are or-ed or added together, e.g.:
 | 
				
			||||||
 | 
					 * #define USB_CFG_DESCR_PROPS_DEVICE   (USB_PROP_IS_RAM | USB_PROP_LENGTH(18))
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The following descriptors are defined:
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_DEVICE
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_CONFIGURATION
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_STRINGS
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_STRING_0
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_STRING_VENDOR
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_STRING_PRODUCT
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_HID
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_HID_REPORT
 | 
				
			||||||
 | 
					 *   USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_DEVICE                  0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_CONFIGURATION           0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRINGS                 0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_0                0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_VENDOR           0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_PRODUCT          0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_HID                     0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_HID_REPORT              0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_UNKNOWN                 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ----------------------- Optional MCU Description ------------------------ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The following configurations have working defaults in usbdrv.h. You
 | 
				
			||||||
 | 
					 * usually don't need to set them explicitly. Only if you want to run
 | 
				
			||||||
 | 
					 * the driver on a device which is not yet supported or with a compiler
 | 
				
			||||||
 | 
					 * which is not fully supported (such as IAR C) or if you use a differnt
 | 
				
			||||||
 | 
					 * interrupt than INT0, you may have to define some of these.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* #define USB_INTR_CFG            MCUCR */
 | 
				
			||||||
 | 
					/* #define USB_INTR_CFG_SET        ((1 << ISC00) | (1 << ISC01)) */
 | 
				
			||||||
 | 
					/* #define USB_INTR_CFG_CLR        0 */
 | 
				
			||||||
 | 
					/* #define USB_INTR_ENABLE         GIMSK */
 | 
				
			||||||
 | 
					/* #define USB_INTR_ENABLE_BIT     INT0 */
 | 
				
			||||||
 | 
					/* #define USB_INTR_PENDING        GIFR */
 | 
				
			||||||
 | 
					/* #define USB_INTR_PENDING_BIT    INTF0 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __usbconfig_h_included__ */
 | 
				
			||||||
							
								
								
									
										572
									
								
								firmware/usbdrv/usbdrv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										572
									
								
								firmware/usbdrv/usbdrv.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,572 @@
 | 
				
			|||||||
 | 
					/* Name: usbdrv.c
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2004-12-29
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: usbdrv.c,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "iarcompat.h"
 | 
				
			||||||
 | 
					#ifndef __IAR_SYSTEMS_ICC__
 | 
				
			||||||
 | 
					#   include <avr/io.h>
 | 
				
			||||||
 | 
					#   include <avr/pgmspace.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#include "usbdrv.h"
 | 
				
			||||||
 | 
					#include "oddebug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					This module implements the C-part of the USB driver. See usbdrv.h for a
 | 
				
			||||||
 | 
					documentation of the entire driver.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef IAR_SECTION
 | 
				
			||||||
 | 
					#define IAR_SECTION(arg)
 | 
				
			||||||
 | 
					#define __no_init
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					/* The macro IAR_SECTION is a hack to allow IAR-cc compatibility. On gcc, it
 | 
				
			||||||
 | 
					 * is defined to nothing. __no_init is required on IAR.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* raw USB registers / interface to assembler code: */
 | 
				
			||||||
 | 
					/* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */
 | 
				
			||||||
 | 
					__no_init uchar usbRxBuf[2][USB_BUFSIZE] __attribute__ ((section (USB_BUFFER_SECTION))) IAR_SECTION(USB_BUFFER_SECTION);/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
 | 
				
			||||||
 | 
					uchar       usbDeviceAddr;      /* assigned during enumeration, defaults to 0 */
 | 
				
			||||||
 | 
					uchar       usbNewDeviceAddr;   /* device ID which should be set after status phase */
 | 
				
			||||||
 | 
					uchar       usbConfiguration;   /* currently selected configuration. Administered by driver, but not used */
 | 
				
			||||||
 | 
					uchar       usbInputBuf;        /* ptr to raw buffer used for receiving */
 | 
				
			||||||
 | 
					uchar       usbAppBuf;          /* ptr to raw buffer passed to app for processing */
 | 
				
			||||||
 | 
					volatile schar usbRxLen;        /* = 0; number of bytes in usbAppBuf; 0 means free */
 | 
				
			||||||
 | 
					uchar       usbCurrentTok;      /* last token received, if more than 1 rx endpoint: MSb=endpoint */
 | 
				
			||||||
 | 
					uchar       usbRxToken;         /* token for data we received; if more than 1 rx endpoint: MSb=endpoint */
 | 
				
			||||||
 | 
					uchar       usbMsgLen = 0xff;   /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */
 | 
				
			||||||
 | 
					volatile uchar usbTxLen = USBPID_NAK;   /* number of bytes to transmit with next IN token or handshake token */
 | 
				
			||||||
 | 
					uchar       usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT
 | 
				
			||||||
 | 
					volatile uchar usbTxLen1 = USBPID_NAK;  /* TX count for endpoint 1 */
 | 
				
			||||||
 | 
					uchar       usbTxBuf1[USB_BUFSIZE];     /* TX data for endpoint 1 */
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					volatile uchar usbTxLen3 = USBPID_NAK;  /* TX count for endpoint 1 */
 | 
				
			||||||
 | 
					uchar       usbTxBuf3[USB_BUFSIZE];     /* TX data for endpoint 1 */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB status registers / not shared with asm code */
 | 
				
			||||||
 | 
					uchar           *usbMsgPtr;     /* data to transmit next -- ROM or RAM address */
 | 
				
			||||||
 | 
					static uchar    usbMsgFlags;    /* flag values see below */
 | 
				
			||||||
 | 
					static uchar    usbIsReset;     /* = 0; USB bus is in reset phase */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_FLG_TX_PACKET       (1<<0)
 | 
				
			||||||
 | 
					/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */
 | 
				
			||||||
 | 
					#define USB_FLG_MSGPTR_IS_ROM   (1<<6)
 | 
				
			||||||
 | 
					#define USB_FLG_USE_DEFAULT_RW  (1<<7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					optimizing hints:
 | 
				
			||||||
 | 
					- do not post/pre inc/dec integer values in operations
 | 
				
			||||||
 | 
					- assign value of PRG_RDB() to register variables and don't use side effects in arg
 | 
				
			||||||
 | 
					- use narrow scope for variables which should be in X/Y/Z register
 | 
				
			||||||
 | 
					- assign char sized expressions to variables to force 8 bit arithmetics
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_STRINGS == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_STRING_0 == 0
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_STRING_0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_0    sizeof(usbDescriptorString0)
 | 
				
			||||||
 | 
					PROGMEM char usbDescriptorString0[] = { /* language descriptor */
 | 
				
			||||||
 | 
					    4,          /* sizeof(usbDescriptorString0): length of descriptor in bytes */
 | 
				
			||||||
 | 
					    3,          /* descriptor type */
 | 
				
			||||||
 | 
					    0x09, 0x04, /* language index (0x0409 = US-English) */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_VENDOR   sizeof(usbDescriptorStringVendor)
 | 
				
			||||||
 | 
					PROGMEM int  usbDescriptorStringVendor[] = {
 | 
				
			||||||
 | 
					    USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
 | 
				
			||||||
 | 
					    USB_CFG_VENDOR_NAME
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_STRING_DEVICE == 0 && USB_CFG_DEVICE_NAME_LEN
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_STRING_DEVICE
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_DEVICE   sizeof(usbDescriptorStringDevice)
 | 
				
			||||||
 | 
					PROGMEM int  usbDescriptorStringDevice[] = {
 | 
				
			||||||
 | 
					    USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
 | 
				
			||||||
 | 
					    USB_CFG_DEVICE_NAME
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    sizeof(usbDescriptorStringSerialNumber)
 | 
				
			||||||
 | 
					PROGMEM int usbDescriptorStringSerialNumber[] = {
 | 
				
			||||||
 | 
					    USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN),
 | 
				
			||||||
 | 
					    USB_CFG_SERIAL_NUMBER
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* USB_CFG_DESCR_PROPS_STRINGS == 0 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_DEVICE == 0
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_DEVICE
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_DEVICE  sizeof(usbDescriptorDevice)
 | 
				
			||||||
 | 
					PROGMEM char usbDescriptorDevice[] = {    /* USB device descriptor */
 | 
				
			||||||
 | 
					    18,         /* sizeof(usbDescriptorDevice): length of descriptor in bytes */
 | 
				
			||||||
 | 
					    USBDESCR_DEVICE,        /* descriptor type */
 | 
				
			||||||
 | 
					    0x01, 0x01,             /* USB version supported */
 | 
				
			||||||
 | 
					    USB_CFG_DEVICE_CLASS,
 | 
				
			||||||
 | 
					    USB_CFG_DEVICE_SUBCLASS,
 | 
				
			||||||
 | 
					    0,                      /* protocol */
 | 
				
			||||||
 | 
					    8,                      /* max packet size */
 | 
				
			||||||
 | 
					    USB_CFG_VENDOR_ID,      /* 2 bytes */
 | 
				
			||||||
 | 
					    USB_CFG_DEVICE_ID,      /* 2 bytes */
 | 
				
			||||||
 | 
					    USB_CFG_DEVICE_VERSION, /* 2 bytes */
 | 
				
			||||||
 | 
					    USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0,         /* manufacturer string index */
 | 
				
			||||||
 | 
					    USB_CFG_DESCR_PROPS_STRING_DEVICE != 0 ? 2 : 0,         /* product string index */
 | 
				
			||||||
 | 
					    USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0,  /* serial number string index */
 | 
				
			||||||
 | 
					    1,          /* number of configurations */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_HID
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_HID     9   /* length of HID descriptor in config descriptor below */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0
 | 
				
			||||||
 | 
					#undef USB_CFG_DESCR_PROPS_CONFIGURATION
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_CONFIGURATION   sizeof(usbDescriptorConfiguration)
 | 
				
			||||||
 | 
					PROGMEM char usbDescriptorConfiguration[] = {    /* USB configuration descriptor */
 | 
				
			||||||
 | 
					    9,          /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
 | 
				
			||||||
 | 
					    USBDESCR_CONFIG,    /* descriptor type */
 | 
				
			||||||
 | 
					    18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff), 0,
 | 
				
			||||||
 | 
					                /* total length of data returned (including inlined descriptors) */
 | 
				
			||||||
 | 
					    1,          /* number of interfaces in this configuration */
 | 
				
			||||||
 | 
					    1,          /* index of this configuration */
 | 
				
			||||||
 | 
					    0,          /* configuration name string index */
 | 
				
			||||||
 | 
					#if USB_CFG_IS_SELF_POWERED
 | 
				
			||||||
 | 
					    USBATTR_SELFPOWER,  /* attributes */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    USBATTR_BUSPOWER,   /* attributes */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    USB_CFG_MAX_BUS_POWER/2,            /* max USB current in 2mA units */
 | 
				
			||||||
 | 
					/* interface descriptor follows inline: */
 | 
				
			||||||
 | 
					    9,          /* sizeof(usbDescrInterface): length of descriptor in bytes */
 | 
				
			||||||
 | 
					    USBDESCR_INTERFACE, /* descriptor type */
 | 
				
			||||||
 | 
					    0,          /* index of this interface */
 | 
				
			||||||
 | 
					    0,          /* alternate setting for this interface */
 | 
				
			||||||
 | 
					    USB_CFG_HAVE_INTRIN_ENDPOINT,   /* endpoints excl 0: number of endpoint descriptors to follow */
 | 
				
			||||||
 | 
					    USB_CFG_INTERFACE_CLASS,
 | 
				
			||||||
 | 
					    USB_CFG_INTERFACE_SUBCLASS,
 | 
				
			||||||
 | 
					    USB_CFG_INTERFACE_PROTOCOL,
 | 
				
			||||||
 | 
					    0,          /* string index for interface */
 | 
				
			||||||
 | 
					#if (USB_CFG_DESCR_PROPS_HID & 0xff)    /* HID descriptor */
 | 
				
			||||||
 | 
					    9,          /* sizeof(usbDescrHID): length of descriptor in bytes */
 | 
				
			||||||
 | 
					    USBDESCR_HID,   /* descriptor type: HID */
 | 
				
			||||||
 | 
					    0x01, 0x01, /* BCD representation of HID version */
 | 
				
			||||||
 | 
					    0x00,       /* target country code */
 | 
				
			||||||
 | 
					    0x01,       /* number of HID Report (or other HID class) Descriptor infos to follow */
 | 
				
			||||||
 | 
					    0x22,       /* descriptor type: report */
 | 
				
			||||||
 | 
					    USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0,  /* total length of report descriptor */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT    /* endpoint descriptor for endpoint 1 */
 | 
				
			||||||
 | 
					    7,          /* sizeof(usbDescrEndpoint) */
 | 
				
			||||||
 | 
					    USBDESCR_ENDPOINT,  /* descriptor type = endpoint */
 | 
				
			||||||
 | 
					    0x81,       /* IN endpoint number 1 */
 | 
				
			||||||
 | 
					    0x03,       /* attrib: Interrupt endpoint */
 | 
				
			||||||
 | 
					    8, 0,       /* maximum packet size */
 | 
				
			||||||
 | 
					    USB_CFG_INTR_POLL_INTERVAL, /* in ms */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* We don't use prog_int or prog_int16_t for compatibility with various libc
 | 
				
			||||||
 | 
					 * versions. Here's an other compatibility hack:
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef PRG_RDB
 | 
				
			||||||
 | 
					#define PRG_RDB(addr)   pgm_read_byte(addr)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef union{
 | 
				
			||||||
 | 
					    unsigned    word;
 | 
				
			||||||
 | 
					    uchar       *ptr;
 | 
				
			||||||
 | 
					    uchar       bytes[2];
 | 
				
			||||||
 | 
					}converter_t;
 | 
				
			||||||
 | 
					/* We use this union to do type conversions. This is better optimized than
 | 
				
			||||||
 | 
					 * type casts in gcc 3.4.3 and much better than using bit shifts to build
 | 
				
			||||||
 | 
					 * ints from chars. Byte ordering is not a problem on an 8 bit platform.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT
 | 
				
			||||||
 | 
					uchar   usbTxPacketCnt1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void    usbSetInterrupt(uchar *data, uchar len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					uchar       *p, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_HALT
 | 
				
			||||||
 | 
					    if(usbTxLen1 == USBPID_STALL)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if 0   /* No runtime checks! Caller is responsible for valid data! */
 | 
				
			||||||
 | 
					    if(len > 8) /* interrupt transfers are limited to 8 bytes */
 | 
				
			||||||
 | 
					        len = 8;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    i = USBPID_DATA1;
 | 
				
			||||||
 | 
					    if(usbTxPacketCnt1 & 1)
 | 
				
			||||||
 | 
					        i = USBPID_DATA0;
 | 
				
			||||||
 | 
					    if(usbTxLen1 & 0x10){       /* packet buffer was empty */
 | 
				
			||||||
 | 
					        usbTxPacketCnt1++;
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					        usbTxLen1 = USBPID_NAK; /* avoid sending incomplete interrupt data */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    p = usbTxBuf1;
 | 
				
			||||||
 | 
					    *p++ = i;
 | 
				
			||||||
 | 
					    for(i=len;i--;)
 | 
				
			||||||
 | 
					        *p++ = *data++;
 | 
				
			||||||
 | 
					    usbCrc16Append(&usbTxBuf1[1], len);
 | 
				
			||||||
 | 
					    usbTxLen1 = len + 4;    /* len must be given including sync byte */
 | 
				
			||||||
 | 
					    DBG2(0x21, usbTxBuf1, len + 3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					uchar   usbTxPacketCnt3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void    usbSetInterrupt3(uchar *data, uchar len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					uchar       *p, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i = USBPID_DATA1;
 | 
				
			||||||
 | 
					    if(usbTxPacketCnt3 & 1)
 | 
				
			||||||
 | 
					        i = USBPID_DATA0;
 | 
				
			||||||
 | 
					    if(usbTxLen3 & 0x10){       /* packet buffer was empty */
 | 
				
			||||||
 | 
					        usbTxPacketCnt3++;
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					        usbTxLen3 = USBPID_NAK; /* avoid sending incomplete interrupt data */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    p = usbTxBuf3;
 | 
				
			||||||
 | 
					    *p++ = i;
 | 
				
			||||||
 | 
					    for(i=len;i--;)
 | 
				
			||||||
 | 
					        *p++ = *data++;
 | 
				
			||||||
 | 
					    usbCrc16Append(&usbTxBuf3[1], len);
 | 
				
			||||||
 | 
					    usbTxLen3 = len + 4;    /* len must be given including sync byte */
 | 
				
			||||||
 | 
					    DBG2(0x23, usbTxBuf3, len + 3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uchar    usbRead(uchar *data, uchar len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_READ
 | 
				
			||||||
 | 
					    if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        uchar i = len, *r = usbMsgPtr;
 | 
				
			||||||
 | 
					        if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){    /* ROM data */
 | 
				
			||||||
 | 
					            while(i--){
 | 
				
			||||||
 | 
					                uchar c = PRG_RDB(r);    /* assign to char size variable to enforce byte ops */
 | 
				
			||||||
 | 
					                *data++ = c;
 | 
				
			||||||
 | 
					                r++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }else{                  /* RAM data */
 | 
				
			||||||
 | 
					            while(i--)
 | 
				
			||||||
 | 
					                *data++ = *r++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        usbMsgPtr = r;
 | 
				
			||||||
 | 
					        return len;
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_READ
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					        if(len != 0)    /* don't bother app with 0 sized reads */
 | 
				
			||||||
 | 
					            return usbFunctionRead(data, len);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define GET_DESCRIPTOR(cfgProp, staticName)         \
 | 
				
			||||||
 | 
					    if(cfgProp){                                    \
 | 
				
			||||||
 | 
					        if((cfgProp) & USB_PROP_IS_RAM)             \
 | 
				
			||||||
 | 
					            flags &= ~USB_FLG_MSGPTR_IS_ROM;        \
 | 
				
			||||||
 | 
					        if((cfgProp) & USB_PROP_IS_DYNAMIC){        \
 | 
				
			||||||
 | 
					            replyLen = usbFunctionDescriptor(rq);   \
 | 
				
			||||||
 | 
					        }else{                                      \
 | 
				
			||||||
 | 
					            replyData = (uchar *)(staticName);      \
 | 
				
			||||||
 | 
					            SET_REPLY_LEN((cfgProp) & 0xff);        \
 | 
				
			||||||
 | 
					        }                                           \
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					/* We use if() instead of #if in the macro above because #if can't be used
 | 
				
			||||||
 | 
					 * in macros and the compiler optimizes constant conditions anyway.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Don't make this function static to avoid inlining.
 | 
				
			||||||
 | 
					 * The entire function would become too large and exceed the range of
 | 
				
			||||||
 | 
					 * relative jumps.
 | 
				
			||||||
 | 
					 * 2006-02-25: Either gcc 3.4.3 is better than the gcc used when the comment
 | 
				
			||||||
 | 
					 * above was written, or other parts of the code have changed. We now get
 | 
				
			||||||
 | 
					 * better results with an inlined function. Test condition: PowerSwitch code.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void usbProcessRx(uchar *data, uchar len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					usbRequest_t    *rq = (void *)data;
 | 
				
			||||||
 | 
					uchar           replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
 | 
				
			||||||
 | 
					/* We use if() cascades because the compare is done byte-wise while switch()
 | 
				
			||||||
 | 
					 * is int-based. The if() cascades are therefore more efficient.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					    DBG2(0x10 + ((usbRxToken >> 6) & 3), data, len);
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_WRITEOUT
 | 
				
			||||||
 | 
					    if(usbRxToken & 0x80){
 | 
				
			||||||
 | 
					        usbFunctionWriteOut(data, len);
 | 
				
			||||||
 | 
					        return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(usbRxToken == (uchar)(USBPID_SETUP & 0x7f)){ /* MSb contains endpoint (== 0) */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    if(usbRxToken == (uchar)USBPID_SETUP){
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        if(len == 8){   /* Setup size must be always 8 bytes. Ignore otherwise. */
 | 
				
			||||||
 | 
					            uchar type = rq->bmRequestType & USBRQ_TYPE_MASK;
 | 
				
			||||||
 | 
					            if(type == USBRQ_TYPE_STANDARD){
 | 
				
			||||||
 | 
					                #define SET_REPLY_LEN(len)  replyLen = (len); usbMsgPtr = replyData
 | 
				
			||||||
 | 
					                /* This macro ensures that replyLen and usbMsgPtr are always set in the same way.
 | 
				
			||||||
 | 
					                 * That allows optimization of common code in if() branches */
 | 
				
			||||||
 | 
					                uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */
 | 
				
			||||||
 | 
					                replyData[0] = 0;   /* common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */
 | 
				
			||||||
 | 
					                if(rq->bRequest == USBRQ_GET_STATUS){           /* 0 */
 | 
				
			||||||
 | 
					                    uchar __attribute__((__unused__)) recipient = rq->bmRequestType & USBRQ_RCPT_MASK;  /* assign arith ops to variables to enforce byte size */
 | 
				
			||||||
 | 
					#if USB_CFG_IS_SELF_POWERED
 | 
				
			||||||
 | 
					                    if(recipient == USBRQ_RCPT_DEVICE)
 | 
				
			||||||
 | 
					                        replyData[0] =  USB_CFG_IS_SELF_POWERED;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_IMPLEMENT_HALT
 | 
				
			||||||
 | 
					                    if(recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81)   /* request status for endpoint 1 */
 | 
				
			||||||
 | 
					                        replyData[0] = usbTxLen1 == USBPID_STALL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					                    replyData[1] = 0;
 | 
				
			||||||
 | 
					                    SET_REPLY_LEN(2);
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_SET_ADDRESS){    /* 5 */
 | 
				
			||||||
 | 
					                    usbNewDeviceAddr = rq->wValue.bytes[0];
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */
 | 
				
			||||||
 | 
					                    flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW;
 | 
				
			||||||
 | 
					                    if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ /* 1 */
 | 
				
			||||||
 | 
					                        GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice)
 | 
				
			||||||
 | 
					                    }else if(rq->wValue.bytes[1] == USBDESCR_CONFIG){   /* 2 */
 | 
				
			||||||
 | 
					                        GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration)
 | 
				
			||||||
 | 
					                    }else if(rq->wValue.bytes[1] == USBDESCR_STRING){   /* 3 */
 | 
				
			||||||
 | 
					#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC
 | 
				
			||||||
 | 
					                        if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					                            flags &= ~USB_FLG_MSGPTR_IS_ROM;
 | 
				
			||||||
 | 
					                        replyLen = usbFunctionDescriptor(rq);
 | 
				
			||||||
 | 
					#else   /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
 | 
				
			||||||
 | 
					                        if(rq->wValue.bytes[0] == 0){   /* descriptor index */
 | 
				
			||||||
 | 
					                            GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0)
 | 
				
			||||||
 | 
					                        }else if(rq->wValue.bytes[0] == 1){
 | 
				
			||||||
 | 
					                            GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor)
 | 
				
			||||||
 | 
					                        }else if(rq->wValue.bytes[0] == 2){
 | 
				
			||||||
 | 
					                            GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_DEVICE, usbDescriptorStringDevice)
 | 
				
			||||||
 | 
					                        }else if(rq->wValue.bytes[0] == 3){
 | 
				
			||||||
 | 
					                            GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber)
 | 
				
			||||||
 | 
					                        }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
 | 
				
			||||||
 | 
					                            replyLen = usbFunctionDescriptor(rq);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					#endif  /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
 | 
				
			||||||
 | 
					                    }else if(rq->wValue.bytes[1] == USBDESCR_HID){          /* 0x21 */
 | 
				
			||||||
 | 
					                        GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18)
 | 
				
			||||||
 | 
					                    }else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){   /* 0x22 */
 | 
				
			||||||
 | 
					                        GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport)
 | 
				
			||||||
 | 
					                    }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
 | 
				
			||||||
 | 
					                        replyLen = usbFunctionDescriptor(rq);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_GET_CONFIGURATION){  /* 8 */
 | 
				
			||||||
 | 
					                    replyData = &usbConfiguration;  /* send current configuration value */
 | 
				
			||||||
 | 
					                    SET_REPLY_LEN(1);
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_SET_CONFIGURATION){  /* 9 */
 | 
				
			||||||
 | 
					                    usbConfiguration = rq->wValue.bytes[0];
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_HALT
 | 
				
			||||||
 | 
					                    usbTxLen1 = USBPID_NAK;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_GET_INTERFACE){      /* 10 */
 | 
				
			||||||
 | 
					                    SET_REPLY_LEN(1);
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_SET_INTERFACE){      /* 11 */
 | 
				
			||||||
 | 
					                    usbTxPacketCnt1 = 0;        /* reset data toggling for interrupt endpoint */
 | 
				
			||||||
 | 
					#   if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					                    usbTxPacketCnt3 = 0;        /* reset data toggling for interrupt endpoint */
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#   if USB_CFG_IMPLEMENT_HALT
 | 
				
			||||||
 | 
					                    usbTxLen1 = USBPID_NAK;
 | 
				
			||||||
 | 
					                }else if(rq->bRequest == USBRQ_CLEAR_FEATURE || rq->bRequest == USBRQ_SET_FEATURE){   /* 1|3 */
 | 
				
			||||||
 | 
					                    if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){   /* feature 0 == HALT for endpoint == 1 */
 | 
				
			||||||
 | 
					                        usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL;
 | 
				
			||||||
 | 
					                        usbTxPacketCnt1 = 0;    /* reset data toggling for interrupt endpoint */
 | 
				
			||||||
 | 
					#       if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					                        usbTxPacketCnt3 = 0;    /* reset data toggling for interrupt endpoint */
 | 
				
			||||||
 | 
					#       endif
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					                }else{
 | 
				
			||||||
 | 
					                    /* the following requests can be ignored, send default reply */
 | 
				
			||||||
 | 
					                    /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
 | 
				
			||||||
 | 
					                    /* 12: SYNCH_FRAME */
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #undef SET_REPLY_LEN
 | 
				
			||||||
 | 
					            }else{  /* not a standard request -- must be vendor or class request */
 | 
				
			||||||
 | 
					                replyLen = usbFunctionSetup(data);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
 | 
				
			||||||
 | 
					            if(replyLen == 0xff){   /* use user-supplied read/write function */
 | 
				
			||||||
 | 
					                if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_DEVICE_TO_HOST){
 | 
				
			||||||
 | 
					                    replyLen = rq->wLength.bytes[0];    /* IN transfers only */
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                flags &= ~USB_FLG_USE_DEFAULT_RW;  /* we have no valid msg, use user supplied read/write functions */
 | 
				
			||||||
 | 
					            }else   /* The 'else' prevents that we limit a replyLen of 0xff to the maximum transfer len. */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0])  /* limit length to max */
 | 
				
			||||||
 | 
					                replyLen = rq->wLength.bytes[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */
 | 
				
			||||||
 | 
					    }else{  /* DATA packet from out request */
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_WRITE
 | 
				
			||||||
 | 
					        if(!(usbMsgFlags & USB_FLG_USE_DEFAULT_RW)){
 | 
				
			||||||
 | 
					            uchar rval = usbFunctionWrite(data, len);
 | 
				
			||||||
 | 
					            replyLen = 0xff;
 | 
				
			||||||
 | 
					            if(rval == 0xff){       /* an error occurred */
 | 
				
			||||||
 | 
					                usbMsgLen = 0xff;   /* cancel potentially pending data packet for ACK */
 | 
				
			||||||
 | 
					                usbTxLen = USBPID_STALL;
 | 
				
			||||||
 | 
					            }else if(rval != 0){    /* This was the final package */
 | 
				
			||||||
 | 
					                replyLen = 0;       /* answer with a zero-sized data packet */
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            flags = 0;    /* start with a DATA1 package, stay with user supplied write() function */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usbMsgFlags = flags;
 | 
				
			||||||
 | 
					    usbMsgLen = replyLen;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usbBuildTxBlock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					uchar       wantLen, len, txLen, token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wantLen = usbMsgLen;
 | 
				
			||||||
 | 
					    if(wantLen > 8)
 | 
				
			||||||
 | 
					        wantLen = 8;
 | 
				
			||||||
 | 
					    usbMsgLen -= wantLen;
 | 
				
			||||||
 | 
					    token = USBPID_DATA1;
 | 
				
			||||||
 | 
					    if(usbMsgFlags & USB_FLG_TX_PACKET)
 | 
				
			||||||
 | 
					        token = USBPID_DATA0;
 | 
				
			||||||
 | 
					    usbMsgFlags++;
 | 
				
			||||||
 | 
					    len = usbRead(usbTxBuf + 1, wantLen);
 | 
				
			||||||
 | 
					    if(len <= 8){           /* valid data packet */
 | 
				
			||||||
 | 
					        usbCrc16Append(&usbTxBuf[1], len);
 | 
				
			||||||
 | 
					        txLen = len + 4;    /* length including sync byte */
 | 
				
			||||||
 | 
					        if(len < 8)         /* a partial package identifies end of message */
 | 
				
			||||||
 | 
					            usbMsgLen = 0xff;
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					        txLen = USBPID_STALL;   /* stall the endpoint */
 | 
				
			||||||
 | 
					        usbMsgLen = 0xff;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    usbTxBuf[0] = token;
 | 
				
			||||||
 | 
					    usbTxLen = txLen;
 | 
				
			||||||
 | 
					    DBG2(0x20, usbTxBuf, txLen-1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline uchar isNotSE0(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					uchar   rval;
 | 
				
			||||||
 | 
					/* We want to do
 | 
				
			||||||
 | 
					 *     return (USBIN & USBMASK);
 | 
				
			||||||
 | 
					 * here, but the compiler does int-expansion acrobatics.
 | 
				
			||||||
 | 
					 * We can avoid this by assigning to a char-sized variable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					    rval = USBIN & USBMASK;
 | 
				
			||||||
 | 
					    return rval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void    usbPoll(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					uchar   len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if((len = usbRxLen) > 0){
 | 
				
			||||||
 | 
					/* We could check CRC16 here -- but ACK has already been sent anyway. If you
 | 
				
			||||||
 | 
					 * need data integrity checks with this driver, check the CRC in your app
 | 
				
			||||||
 | 
					 * code and report errors back to the host. Since the ACK was already sent,
 | 
				
			||||||
 | 
					 * retries must be handled on application level.
 | 
				
			||||||
 | 
					 * unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3);
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					        len -= 3;       /* remove PID and CRC */
 | 
				
			||||||
 | 
					        if(len < 128){  /* no overflow */
 | 
				
			||||||
 | 
					            converter_t appBuf;
 | 
				
			||||||
 | 
					            appBuf.ptr = (uchar *)usbRxBuf;
 | 
				
			||||||
 | 
					            appBuf.bytes[0] = usbAppBuf;
 | 
				
			||||||
 | 
					            appBuf.bytes[0]++;
 | 
				
			||||||
 | 
					            usbProcessRx(appBuf.ptr, len);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_FLOWCONTROL
 | 
				
			||||||
 | 
					        if(usbRxLen > 0)    /* only mark as available if not inactivated */
 | 
				
			||||||
 | 
					            usbRxLen = 0;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        usbRxLen = 0;   /* mark rx buffer as available */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(usbMsgLen != 0xff){  /* transmit data pending? */
 | 
				
			||||||
 | 
					        if(usbTxLen & 0x10) /* transmit system idle */
 | 
				
			||||||
 | 
					            usbBuildTxBlock();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(isNotSE0()){ /* SE0 state */
 | 
				
			||||||
 | 
					        usbIsReset = 0;
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					        /* check whether SE0 lasts for more than 2.5us (3.75 bit times) */
 | 
				
			||||||
 | 
					        if(!usbIsReset){
 | 
				
			||||||
 | 
					            uchar i;
 | 
				
			||||||
 | 
					            for(i=100;i;i--){
 | 
				
			||||||
 | 
					                if(isNotSE0())
 | 
				
			||||||
 | 
					                    goto notUsbReset;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            usbIsReset = 1;
 | 
				
			||||||
 | 
					            usbNewDeviceAddr = 0;
 | 
				
			||||||
 | 
					            usbDeviceAddr = 0;
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_HALT
 | 
				
			||||||
 | 
					            usbTxLen1 = USBPID_NAK;
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					            usbTxLen3 = USBPID_NAK;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            DBG1(0xff, 0, 0);
 | 
				
			||||||
 | 
					notUsbReset:;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void    usbInit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    usbInputBuf = (uchar)usbRxBuf[0];
 | 
				
			||||||
 | 
					    usbAppBuf = (uchar)usbRxBuf[1];
 | 
				
			||||||
 | 
					#if USB_INTR_CFG_SET != 0
 | 
				
			||||||
 | 
					    USB_INTR_CFG |= USB_INTR_CFG_SET;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if USB_INTR_CFG_CLR != 0
 | 
				
			||||||
 | 
					    USB_INTR_CFG &= ~(USB_INTR_CFG_CLR);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
							
								
								
									
										657
									
								
								firmware/usbdrv/usbdrv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										657
									
								
								firmware/usbdrv/usbdrv.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,657 @@
 | 
				
			|||||||
 | 
					/* Name: usbdrv.h
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2004-12-29
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: usbdrv.h,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __usbdrv_h_included__
 | 
				
			||||||
 | 
					#define __usbdrv_h_included__
 | 
				
			||||||
 | 
					#include "usbconfig.h"
 | 
				
			||||||
 | 
					#include "iarcompat.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Hardware Prerequisites:
 | 
				
			||||||
 | 
					=======================
 | 
				
			||||||
 | 
					USB lines D+ and D- MUST be wired to the same I/O port. D+ must (also) be
 | 
				
			||||||
 | 
					connected to INT0. D- requires a pullup of 1.5k to +3.5V (and the device
 | 
				
			||||||
 | 
					must be powered at 3.5V) to identify as low-speed USB device. A pullup of
 | 
				
			||||||
 | 
					1M SHOULD be connected from D+ to +3.5V to prevent interference when no USB
 | 
				
			||||||
 | 
					master is connected. We use D+ as interrupt source and not D- because it
 | 
				
			||||||
 | 
					does not trigger on keep-alive and RESET states.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As a compile time option, the 1.5k pullup resistor on D- can be made
 | 
				
			||||||
 | 
					switchable to allow the device to disconnect at will. See the definition of
 | 
				
			||||||
 | 
					usbDeviceConnect() and usbDeviceDisconnect() further down in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please adapt the values in usbconfig.h according to your hardware!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The device MUST be clocked at 12 MHz. This is more than the 10 MHz allowed by
 | 
				
			||||||
 | 
					an AT90S2313 powered at 4.5V. However, if the supply voltage to maximum clock
 | 
				
			||||||
 | 
					relation is interpolated linearly, an ATtiny2313 meets the requirement by
 | 
				
			||||||
 | 
					specification. In practice, the AT90S2313 can be overclocked and works well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Limitations:
 | 
				
			||||||
 | 
					============
 | 
				
			||||||
 | 
					Compiling:
 | 
				
			||||||
 | 
					You should link the usbdrv.o module first because it has special alignment
 | 
				
			||||||
 | 
					requirements for the receive buffer (the buffer must not cross a 256 byte
 | 
				
			||||||
 | 
					page boundary, it must not even touch it at the end). If you can't link it
 | 
				
			||||||
 | 
					first, you must use other measures to ensure alignment.
 | 
				
			||||||
 | 
					Note: gcc does not always assign variable addresses in the order as the modules
 | 
				
			||||||
 | 
					are linked or the variables are declared. You can choose a memory section for
 | 
				
			||||||
 | 
					the receive buffer with the configuration option "USB_BUFFER_SECTION". This
 | 
				
			||||||
 | 
					option defaults to ".bss". If you use your own section, you can place it at
 | 
				
			||||||
 | 
					an arbitrary location with a linker option similar to
 | 
				
			||||||
 | 
					"-Wl,--section-start=.mybuffer=0x800060". Use "avr-nm -ng" on the binary and
 | 
				
			||||||
 | 
					search for "usbRxBuf" to find tbe base address of the 22 bytes rx buffer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Robustness with respect to communication errors:
 | 
				
			||||||
 | 
					The driver assumes error-free communication. It DOES check for errors in
 | 
				
			||||||
 | 
					the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte,
 | 
				
			||||||
 | 
					token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due
 | 
				
			||||||
 | 
					to timing constraints: We must start sending a reply within 7 bit times.
 | 
				
			||||||
 | 
					Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU
 | 
				
			||||||
 | 
					performance does not permit that. The driver does not check Data0/Data1
 | 
				
			||||||
 | 
					toggling, but application software can implement the check.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sampling jitter:
 | 
				
			||||||
 | 
					The driver guarantees a sampling window of 1/2 bit. The USB spec requires
 | 
				
			||||||
 | 
					that the receiver has at most 1/4 bit sampling window. The 1/2 bit window
 | 
				
			||||||
 | 
					should still work reliably enough because we work at low speed. If you want
 | 
				
			||||||
 | 
					to meet the spec, define the macro "USB_CFG_SAMPLE_EXACT" to 1 in usbconfig.h.
 | 
				
			||||||
 | 
					This will unroll a loop which results in bigger code size.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Input characteristics:
 | 
				
			||||||
 | 
					Since no differential receiver circuit is used, electrical interference
 | 
				
			||||||
 | 
					robustness may suffer. The driver samples only one of the data lines with
 | 
				
			||||||
 | 
					an ordinary I/O pin's input characteristics. However, since this is only a
 | 
				
			||||||
 | 
					low speed USB implementation and the specification allows for 8 times the
 | 
				
			||||||
 | 
					bit rate over the same hardware, we should be on the safe side. Even the spec
 | 
				
			||||||
 | 
					requires detection of asymmetric states at high bit rate for SE0 detection.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Number of endpoints:
 | 
				
			||||||
 | 
					The driver supports up to four endpoints: One control endpoint (endpoint 0),
 | 
				
			||||||
 | 
					two interrupt-in (or bulk-in) endpoints (endpoint 1 and 3) and one
 | 
				
			||||||
 | 
					interrupt-out (or bulk-out) endpoint (endpoint 1). Please note that the USB
 | 
				
			||||||
 | 
					standard forbids bulk endpoints for low speed devices! Most operating systems
 | 
				
			||||||
 | 
					allow them anyway, but the AVR will spend 90% of the CPU time in the USB
 | 
				
			||||||
 | 
					interrupt polling for bulk data.
 | 
				
			||||||
 | 
					By default, only the control endpoint 0 is enabled. To get the other endpoints,
 | 
				
			||||||
 | 
					define USB_CFG_HAVE_INTRIN_ENDPOINT, USB_CFG_HAVE_INTRIN_ENDPOINT3 and/or
 | 
				
			||||||
 | 
					USB_CFG_IMPLEMENT_FN_WRITEOUT respectively (see usbconfig-prototype.h for
 | 
				
			||||||
 | 
					details).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Maximum data payload:
 | 
				
			||||||
 | 
					Data payload of control in and out transfers may be up to 254 bytes. In order
 | 
				
			||||||
 | 
					to accept payload data of out transfers, you need to implement
 | 
				
			||||||
 | 
					'usbFunctionWrite()'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USB Suspend Mode supply current:
 | 
				
			||||||
 | 
					The USB standard limits power consumption to 500uA when the bus is in suspend
 | 
				
			||||||
 | 
					mode. This is not a problem for self-powered devices since they don't need
 | 
				
			||||||
 | 
					bus power anyway. Bus-powered devices can achieve this only by putting the
 | 
				
			||||||
 | 
					CPU in sleep mode. The driver does not implement suspend handling by itself.
 | 
				
			||||||
 | 
					However, the application may implement activity monitoring and wakeup from
 | 
				
			||||||
 | 
					sleep. The host sends regular SE0 states on the bus to keep it active. These
 | 
				
			||||||
 | 
					SE0 states can be detected by wiring the INT1 pin to D-. It is not necessary
 | 
				
			||||||
 | 
					to enable the interrupt, checking the interrupt pending flag should suffice.
 | 
				
			||||||
 | 
					Before entering sleep mode, the application should enable INT1 for a wakeup
 | 
				
			||||||
 | 
					on the next bus activity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Operation without an USB master:
 | 
				
			||||||
 | 
					The driver behaves neutral without connection to an USB master if D- reads
 | 
				
			||||||
 | 
					as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M)
 | 
				
			||||||
 | 
					pullup resistor on D+. If D- becomes statically 0, the driver may block in
 | 
				
			||||||
 | 
					the interrupt routine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Interrupt latency:
 | 
				
			||||||
 | 
					The application must ensure that the USB interrupt is not disabled for more
 | 
				
			||||||
 | 
					than 20 cycles. This implies that all interrupt routines must either be
 | 
				
			||||||
 | 
					declared as "INTERRUPT" instead of "SIGNAL" (see "avr/signal.h") or that they
 | 
				
			||||||
 | 
					are written in assembler with "sei" as the first instruction.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Maximum interrupt duration / CPU cycle consumption:
 | 
				
			||||||
 | 
					The driver handles all USB communication during the interrupt service
 | 
				
			||||||
 | 
					routine. The routine will not return before an entire USB message is received
 | 
				
			||||||
 | 
					and the reply is sent. This may be up to ca. 1200 cycles = 100us if the host
 | 
				
			||||||
 | 
					conforms to the standard. The driver will consume CPU cycles for all USB
 | 
				
			||||||
 | 
					messages, even if they address another (low-speed) device on the same bus.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					/* --------------------------- Module Interface ---------------------------- */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBDRV_VERSION  20060718
 | 
				
			||||||
 | 
					/* This define uniquely identifies a driver version. It is a decimal number
 | 
				
			||||||
 | 
					 * constructed from the driver's release date in the form YYYYMMDD. If the
 | 
				
			||||||
 | 
					 * driver's behavior or interface changes, you can use this constant to
 | 
				
			||||||
 | 
					 * distinguish versions. If it is not defined, the driver's release date is
 | 
				
			||||||
 | 
					 * older than 2006-01-25.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLER__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef uchar
 | 
				
			||||||
 | 
					#define uchar   unsigned char
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef schar
 | 
				
			||||||
 | 
					#define schar   signed char
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					/* shortcuts for well defined 8 bit integer types */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usbRequest;  /* forward declaration */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void     usbInit(void);
 | 
				
			||||||
 | 
					/* This function must be called before interrupts are enabled and the main
 | 
				
			||||||
 | 
					 * loop is entered.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern void     usbPoll(void);
 | 
				
			||||||
 | 
					/* This function must be called at regular intervals from the main loop.
 | 
				
			||||||
 | 
					 * Maximum delay between calls is somewhat less than 50ms (USB timeout for
 | 
				
			||||||
 | 
					 * accepting a Setup message). Otherwise the device will not be recognized.
 | 
				
			||||||
 | 
					 * Please note that debug outputs through the UART take ~ 0.5ms per byte
 | 
				
			||||||
 | 
					 * at 19200 bps.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern uchar    *usbMsgPtr;
 | 
				
			||||||
 | 
					/* This variable may be used to pass transmit data to the driver from the
 | 
				
			||||||
 | 
					 * implementation of usbFunctionWrite(). It is also used internally by the
 | 
				
			||||||
 | 
					 * driver for standard control requests.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern uchar    usbFunctionSetup(uchar data[8]);
 | 
				
			||||||
 | 
					/* This function is called when the driver receives a SETUP transaction from
 | 
				
			||||||
 | 
					 * the host which is not answered by the driver itself (in practice: class and
 | 
				
			||||||
 | 
					 * vendor requests). All control transfers start with a SETUP transaction where
 | 
				
			||||||
 | 
					 * the host communicates the parameters of the following (optional) data
 | 
				
			||||||
 | 
					 * transfer. The SETUP data is available in the 'data' parameter which can
 | 
				
			||||||
 | 
					 * (and should) be casted to 'usbRequest_t *' for a more user-friendly access
 | 
				
			||||||
 | 
					 * to parameters.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the SETUP indicates a control-in transfer, you should provide the
 | 
				
			||||||
 | 
					 * requested data to the driver. There are two ways to transfer this data:
 | 
				
			||||||
 | 
					 * (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data
 | 
				
			||||||
 | 
					 * block and return the length of the data in 'usbFunctionSetup()'. The driver
 | 
				
			||||||
 | 
					 * will handle the rest. Or (2) return 0xff in 'usbFunctionSetup()'. The driver
 | 
				
			||||||
 | 
					 * will then call 'usbFunctionRead()' when data is needed. See the
 | 
				
			||||||
 | 
					 * documentation for usbFunctionRead() for details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the SETUP indicates a control-out transfer, the only way to receive the
 | 
				
			||||||
 | 
					 * data from the host is through the 'usbFunctionWrite()' call. If you
 | 
				
			||||||
 | 
					 * implement this function, you must return 0xff in 'usbFunctionSetup()' to
 | 
				
			||||||
 | 
					 * indicate that 'usbFunctionWrite()' should be used. See the documentation of
 | 
				
			||||||
 | 
					 * this function for more information. If you just want to ignore the data sent
 | 
				
			||||||
 | 
					 * by the host, return 0 in 'usbFunctionSetup()'.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that calls to the functions usbFunctionRead() and usbFunctionWrite()
 | 
				
			||||||
 | 
					 * are only done if enabled by the configuration in usbconfig.h.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern uchar usbFunctionDescriptor(struct usbRequest *rq);
 | 
				
			||||||
 | 
					/* You need to implement this function ONLY if you provide USB descriptors at
 | 
				
			||||||
 | 
					 * runtime (which is an expert feature). It is very similar to
 | 
				
			||||||
 | 
					 * usbFunctionSetup() above, but it is called only to request USB descriptor
 | 
				
			||||||
 | 
					 * data. See the documentation of usbFunctionSetup() above for more info.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT
 | 
				
			||||||
 | 
					void    usbSetInterrupt(uchar *data, uchar len);
 | 
				
			||||||
 | 
					/* This function sets the message which will be sent during the next interrupt
 | 
				
			||||||
 | 
					 * IN transfer. The message is copied to an internal buffer and must not exceed
 | 
				
			||||||
 | 
					 * a length of 8 bytes. The message may be 0 bytes long just to indicate the
 | 
				
			||||||
 | 
					 * interrupt status to the host.
 | 
				
			||||||
 | 
					 * If you need to transfer more bytes, use a control read after the interrupt.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern volatile uchar usbTxLen1;
 | 
				
			||||||
 | 
					#define usbInterruptIsReady()   (usbTxLen1 & 0x10)
 | 
				
			||||||
 | 
					/* This macro indicates whether the last interrupt message has already been
 | 
				
			||||||
 | 
					 * sent. If you set a new interrupt message before the old was sent, the
 | 
				
			||||||
 | 
					 * message already buffered will be lost.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					void    usbSetInterrupt3(uchar *data, uchar len);
 | 
				
			||||||
 | 
					extern volatile uchar usbTxLen3;
 | 
				
			||||||
 | 
					#define usbInterruptIsReady3()   (usbTxLen3 & 0x10)
 | 
				
			||||||
 | 
					/* Same as above for endpoint 3 */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
 | 
				
			||||||
 | 
					#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    /* simplified interface for backward compatibility */
 | 
				
			||||||
 | 
					#define usbHidReportDescriptor  usbDescriptorHidReport
 | 
				
			||||||
 | 
					/* should be declared as: PROGMEM char usbHidReportDescriptor[]; */
 | 
				
			||||||
 | 
					/* If you implement an HID device, you need to provide a report descriptor.
 | 
				
			||||||
 | 
					 * The HID report descriptor syntax is a bit complex. If you understand how
 | 
				
			||||||
 | 
					 * report descriptors are constructed, we recommend that you use the HID
 | 
				
			||||||
 | 
					 * Descriptor Tool from usb.org, see http://www.usb.org/developers/hidpage/.
 | 
				
			||||||
 | 
					 * Otherwise you should probably start with a working example.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif  /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_WRITE
 | 
				
			||||||
 | 
					extern uchar    usbFunctionWrite(uchar *data, uchar len);
 | 
				
			||||||
 | 
					/* This function is called by the driver to provide a control transfer's
 | 
				
			||||||
 | 
					 * payload data (control-out). It is called in chunks of up to 8 bytes. The
 | 
				
			||||||
 | 
					 * total count provided in the current control transfer can be obtained from
 | 
				
			||||||
 | 
					 * the 'length' property in the setup data. If an error occurred during
 | 
				
			||||||
 | 
					 * processing, return 0xff (== -1). The driver will answer the entire transfer
 | 
				
			||||||
 | 
					 * with a STALL token in this case. If you have received the entire payload
 | 
				
			||||||
 | 
					 * successfully, return 1. If you expect more data, return 0. If you don't
 | 
				
			||||||
 | 
					 * know whether the host will send more data (you should know, the total is
 | 
				
			||||||
 | 
					 * provided in the usbFunctionSetup() call!), return 1.
 | 
				
			||||||
 | 
					 * NOTE: If you return 0xff for STALL, 'usbFunctionWrite()' may still be called
 | 
				
			||||||
 | 
					 * for the remaining data. You must continue to return 0xff for STALL in these
 | 
				
			||||||
 | 
					 * calls.
 | 
				
			||||||
 | 
					 * In order to get usbFunctionWrite() called, define USB_CFG_IMPLEMENT_FN_WRITE
 | 
				
			||||||
 | 
					 * to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_READ
 | 
				
			||||||
 | 
					extern uchar usbFunctionRead(uchar *data, uchar len);
 | 
				
			||||||
 | 
					/* This function is called by the driver to ask the application for a control
 | 
				
			||||||
 | 
					 * transfer's payload data (control-in). It is called in chunks of up to 8
 | 
				
			||||||
 | 
					 * bytes each. You should copy the data to the location given by 'data' and
 | 
				
			||||||
 | 
					 * return the actual number of bytes copied. If you return less than requested,
 | 
				
			||||||
 | 
					 * the control-in transfer is terminated. If you return 0xff, the driver aborts
 | 
				
			||||||
 | 
					 * the transfer with a STALL token.
 | 
				
			||||||
 | 
					 * In order to get usbFunctionRead() called, define USB_CFG_IMPLEMENT_FN_READ
 | 
				
			||||||
 | 
					 * to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif /* USB_CFG_IMPLEMENT_FN_READ */
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_WRITEOUT
 | 
				
			||||||
 | 
					extern void usbFunctionWriteOut(uchar *data, uchar len);
 | 
				
			||||||
 | 
					/* This function is called by the driver when data on interrupt-out or bulk-
 | 
				
			||||||
 | 
					 * out endpoint 1 is received. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT
 | 
				
			||||||
 | 
					 * to 1 in usbconfig.h to get this function called.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */
 | 
				
			||||||
 | 
					#ifdef USB_CFG_PULLUP_IOPORTNAME
 | 
				
			||||||
 | 
					#define usbDeviceConnect()      ((USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT)), \
 | 
				
			||||||
 | 
					                                  (USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT)))
 | 
				
			||||||
 | 
					/* This macro (intended to look like a function) connects the device to the
 | 
				
			||||||
 | 
					 * USB bus. It is only available if you have defined the constants
 | 
				
			||||||
 | 
					 * USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define usbDeviceDisconnect()   (USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT))
 | 
				
			||||||
 | 
					/* This macro (intended to look like a function) disconnects the device from
 | 
				
			||||||
 | 
					 * the USB bus. It is only available if you have defined the constants
 | 
				
			||||||
 | 
					 * USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif /* USB_CFG_PULLUP_IOPORT */
 | 
				
			||||||
 | 
					extern unsigned usbCrc16(unsigned data, uchar len);
 | 
				
			||||||
 | 
					#define usbCrc16(data, len) usbCrc16((unsigned)(data), len)
 | 
				
			||||||
 | 
					/* This function calculates the binary complement of the data CRC used in
 | 
				
			||||||
 | 
					 * USB data packets. The value is used to build raw transmit packets.
 | 
				
			||||||
 | 
					 * You may want to use this function for data checksums or to verify received
 | 
				
			||||||
 | 
					 * data. We enforce 16 bit calling conventions for compatibility with IAR's
 | 
				
			||||||
 | 
					 * tiny memory model.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern unsigned usbCrc16Append(unsigned data, uchar len);
 | 
				
			||||||
 | 
					#define usbCrc16Append(data, len)    usbCrc16Append((unsigned)(data), len)
 | 
				
			||||||
 | 
					/* This function is equivalent to usbCrc16() above, except that it appends
 | 
				
			||||||
 | 
					 * the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len'
 | 
				
			||||||
 | 
					 * bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					extern uchar    usbConfiguration;
 | 
				
			||||||
 | 
					/* This value contains the current configuration set by the host. The driver
 | 
				
			||||||
 | 
					 * allows setting and querying of this variable with the USB SET_CONFIGURATION
 | 
				
			||||||
 | 
					 * and GET_CONFIGURATION requests, but does not use it otherwise.
 | 
				
			||||||
 | 
					 * You may want to reflect the "configured" status with a LED on the device or
 | 
				
			||||||
 | 
					 * switch on high power parts of the circuit only if the device is configured.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8))
 | 
				
			||||||
 | 
					/* This macro builds a descriptor header for a string descriptor given the
 | 
				
			||||||
 | 
					 * string's length. See usbdrv.c for an example how to use it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_FLOWCONTROL
 | 
				
			||||||
 | 
					extern volatile schar   usbRxLen;
 | 
				
			||||||
 | 
					#define usbDisableAllRequests()     usbRxLen = -1
 | 
				
			||||||
 | 
					/* Must be called from usbFunctionWrite(). This macro disables all data input
 | 
				
			||||||
 | 
					 * from the USB interface. Requests from the host are answered with a NAK
 | 
				
			||||||
 | 
					 * while they are disabled.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define usbEnableAllRequests()      usbRxLen = 0
 | 
				
			||||||
 | 
					/* May only be called if requests are disabled. This macro enables input from
 | 
				
			||||||
 | 
					 * the USB interface after it has been disabled with usbDisableAllRequests().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define usbAllRequestsAreDisabled() (usbRxLen < 0)
 | 
				
			||||||
 | 
					/* Use this macro to find out whether requests are disabled. It may be needed
 | 
				
			||||||
 | 
					 * to ensure that usbEnableAllRequests() is never called when requests are
 | 
				
			||||||
 | 
					 * enabled.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern uchar    usbTxPacketCnt1;
 | 
				
			||||||
 | 
					extern uchar    usbTxPacketCnt3;
 | 
				
			||||||
 | 
					/* The two variables above are mostly for internal use by the driver. You may
 | 
				
			||||||
 | 
					 * have to reset usbTxPacketCnt1 to 0 if you start data toggling at DATA0 for
 | 
				
			||||||
 | 
					 * interrupt-IN endpoint 1 and usbTxPacketCnt3 for interrupt-IN endpoint 3
 | 
				
			||||||
 | 
					 * respectively.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* __ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					/* ----------------- Definitions for Descriptor Properties ----------------- */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					/* This is advanced stuff. See usbconfig-prototype.h for more information
 | 
				
			||||||
 | 
					 * about the various methods to define USB descriptors. If you do nothing,
 | 
				
			||||||
 | 
					 * the default descriptors will be used.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_PROP_IS_DYNAMIC     (1 << 8)
 | 
				
			||||||
 | 
					/* If this property is set for a descriptor, usbFunctionDescriptor() will be
 | 
				
			||||||
 | 
					 * used to obtain the particular descriptor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_PROP_IS_RAM         (1 << 9)
 | 
				
			||||||
 | 
					/* If this property is set for a descriptor, the data is read from RAM
 | 
				
			||||||
 | 
					 * memory instead of Flash. The property is used for all methods to provide
 | 
				
			||||||
 | 
					 * external descriptors.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define USB_PROP_LENGTH(len)    ((len) & 0xff)
 | 
				
			||||||
 | 
					/* If a static external descriptor is used, this is the total length of the
 | 
				
			||||||
 | 
					 * descriptor in bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* all descriptors which may have properties: */
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_DEVICE
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_DEVICE                  0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_CONFIGURATION
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_CONFIGURATION           0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_STRINGS
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRINGS                 0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_STRING_0
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_0                0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_VENDOR           0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_STRING_DEVICE
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_DEVICE           0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_HID
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_HID                     0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_HID_REPORT)
 | 
				
			||||||
 | 
					#   undef USB_CFG_DESCR_PROPS_HID_REPORT
 | 
				
			||||||
 | 
					#   if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* do some backward compatibility tricks */
 | 
				
			||||||
 | 
					#       define USB_CFG_DESCR_PROPS_HID_REPORT       USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
 | 
				
			||||||
 | 
					#   else
 | 
				
			||||||
 | 
					#       define USB_CFG_DESCR_PROPS_HID_REPORT       0
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DESCR_PROPS_UNKNOWN
 | 
				
			||||||
 | 
					#define USB_CFG_DESCR_PROPS_UNKNOWN                 0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------ forward declaration of descriptors ------------------- */
 | 
				
			||||||
 | 
					/* If you use external static descriptors, they must be stored in global
 | 
				
			||||||
 | 
					 * arrays as declared below:
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLER__
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					char usbDescriptorDevice[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					char usbDescriptorConfiguration[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					char usbDescriptorHidReport[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					char usbDescriptorString0[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					int usbDescriptorStringVendor[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					int usbDescriptorStringDevice[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern
 | 
				
			||||||
 | 
					#if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM)
 | 
				
			||||||
 | 
					PROGMEM
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					int usbDescriptorStringSerialNumber[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					/* ------------------------ General Purpose Macros ------------------------- */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_CONCAT(a, b)            a ## b
 | 
				
			||||||
 | 
					#define USB_CONCAT_EXPANDED(a, b)   USB_CONCAT(a, b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_OUTPORT(name)           USB_CONCAT(PORT, name)
 | 
				
			||||||
 | 
					#define USB_INPORT(name)            USB_CONCAT(PIN, name)
 | 
				
			||||||
 | 
					#define USB_DDRPORT(name)           USB_CONCAT(DDR, name)
 | 
				
			||||||
 | 
					/* The double-define trick above lets us concatenate strings which are
 | 
				
			||||||
 | 
					 * defined by macros.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					/* ------------------------- Constant definitions -------------------------- */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID
 | 
				
			||||||
 | 
					static uchar Warning_You_should_define_USB_CFG_VENDOR_ID_and_USB_CFG_DEVICE_ID_in_usbconfig_h;
 | 
				
			||||||
 | 
					/* The unused variable above should generate a warning on all compilers. IAR cc
 | 
				
			||||||
 | 
					 * does not understand the "#warning" preprocessor direcetive.
 | 
				
			||||||
 | 
					 * If the user has not defined IDs, we default to obdev's free IDs.
 | 
				
			||||||
 | 
					 * See USBID-License.txt for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* make sure we have a VID and PID defined, byte order is lowbyte, highbyte */
 | 
				
			||||||
 | 
					#ifndef USB_CFG_VENDOR_ID
 | 
				
			||||||
 | 
					#   define  USB_CFG_VENDOR_ID   0xc0, 0x16  /* 5824 in dec, stands for VOTI */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_CFG_DEVICE_ID
 | 
				
			||||||
 | 
					#   if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
 | 
				
			||||||
 | 
					#       define USB_CFG_DEVICE_ID    0xdf, 0x05  /* 1503 in dec, shared PID for HIDs */
 | 
				
			||||||
 | 
					#   elif USB_CFG_INTERFACE_CLASS == 2
 | 
				
			||||||
 | 
					#       define USB_CFG_DEVICE_ID    0xe1, 0x05  /* 1505 in dec, shared PID for CDC Modems */
 | 
				
			||||||
 | 
					#   else
 | 
				
			||||||
 | 
					#       define USB_CFG_DEVICE_ID    0xdc, 0x05  /* 1500 in dec, obdev's free PID */
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_BUFFER_SECTION
 | 
				
			||||||
 | 
					#   define  USB_BUFFER_SECTION  ".bss"      /* if user has not selected a named section */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derive Output, Input and DataDirection ports from port names */
 | 
				
			||||||
 | 
					#ifndef USB_CFG_IOPORTNAME
 | 
				
			||||||
 | 
					#error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBOUT          USB_OUTPORT(USB_CFG_IOPORTNAME)
 | 
				
			||||||
 | 
					#define USB_PULLUP_OUT  USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
 | 
				
			||||||
 | 
					#define USBIN           USB_INPORT(USB_CFG_IOPORTNAME)
 | 
				
			||||||
 | 
					#define USBDDR          USB_DDRPORT(USB_CFG_IOPORTNAME)
 | 
				
			||||||
 | 
					#define USB_PULLUP_DDR  USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBMINUS    USB_CFG_DMINUS_BIT
 | 
				
			||||||
 | 
					#define USBPLUS     USB_CFG_DPLUS_BIT
 | 
				
			||||||
 | 
					#define USBIDLE     (1<<USB_CFG_DMINUS_BIT) /* value representing J state */
 | 
				
			||||||
 | 
					#define USBMASK     ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT))  /* mask for USB I/O bits */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* defines for backward compatibility with older driver versions: */
 | 
				
			||||||
 | 
					#define USB_CFG_IOPORT          USB_OUTPORT(USB_CFG_IOPORTNAME)
 | 
				
			||||||
 | 
					#ifdef USB_CFG_PULLUP_IOPORTNAME
 | 
				
			||||||
 | 
					#define USB_CFG_PULLUP_IOPORT   USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USB_BUFSIZE     11  /* PID, 8 bytes data, 2 bytes CRC */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_INTR_CFG    /* allow user to override our default */
 | 
				
			||||||
 | 
					#   if defined  EICRA
 | 
				
			||||||
 | 
					#       define USB_INTR_CFG EICRA
 | 
				
			||||||
 | 
					#   else
 | 
				
			||||||
 | 
					#       define USB_INTR_CFG MCUCR
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_INTR_CFG_SET    /* allow user to override our default */
 | 
				
			||||||
 | 
					#   define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01))    /* cfg for rising edge */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_INTR_CFG_CLR    /* allow user to override our default */
 | 
				
			||||||
 | 
					#   define USB_INTR_CFG_CLR 0    /* no bits to clear */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_INTR_ENABLE     /* allow user to override our default */
 | 
				
			||||||
 | 
					#   if defined GIMSK
 | 
				
			||||||
 | 
					#       define USB_INTR_ENABLE  GIMSK
 | 
				
			||||||
 | 
					#   elif defined EIMSK
 | 
				
			||||||
 | 
					#       define USB_INTR_ENABLE  EIMSK
 | 
				
			||||||
 | 
					#   else
 | 
				
			||||||
 | 
					#       define USB_INTR_ENABLE  GICR
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */
 | 
				
			||||||
 | 
					#   define USB_INTR_ENABLE_BIT  INT0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USB_INTR_PENDING    /* allow user to override our default */
 | 
				
			||||||
 | 
					#   if defined  EIFR
 | 
				
			||||||
 | 
					#       define USB_INTR_PENDING EIFR
 | 
				
			||||||
 | 
					#   else
 | 
				
			||||||
 | 
					#       define USB_INTR_PENDING GIFR
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef USB_INTR_PENDING_BIT    /* allow user to override our default */
 | 
				
			||||||
 | 
					#   define USB_INTR_PENDING_BIT INTF0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					The defines above don't work for the following chips
 | 
				
			||||||
 | 
					at90c8534: no ISC0?, no PORTB, can't find a data sheet
 | 
				
			||||||
 | 
					at86rf401: no PORTB, no MCUCR etc, low clock rate
 | 
				
			||||||
 | 
					atmega103: no ISC0? (maybe omission in header, can't find data sheet)
 | 
				
			||||||
 | 
					atmega603: not defined in avr-libc
 | 
				
			||||||
 | 
					at43usb320, at43usb355, at76c711: have USB anyway
 | 
				
			||||||
 | 
					at94k: is different...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					/* ----------------- USB Specification Constants and Types ----------------- */
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB Token values */
 | 
				
			||||||
 | 
					#define USBPID_SETUP    0x2d
 | 
				
			||||||
 | 
					#define USBPID_OUT      0xe1
 | 
				
			||||||
 | 
					#define USBPID_IN       0x69
 | 
				
			||||||
 | 
					#define USBPID_DATA0    0xc3
 | 
				
			||||||
 | 
					#define USBPID_DATA1    0x4b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBPID_ACK      0xd2
 | 
				
			||||||
 | 
					#define USBPID_NAK      0x5a
 | 
				
			||||||
 | 
					#define USBPID_STALL    0x1e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLER__
 | 
				
			||||||
 | 
					typedef union usbWord{
 | 
				
			||||||
 | 
					    unsigned    word;
 | 
				
			||||||
 | 
					    uchar       bytes[2];
 | 
				
			||||||
 | 
					}usbWord_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct usbRequest{
 | 
				
			||||||
 | 
					    uchar       bmRequestType;
 | 
				
			||||||
 | 
					    uchar       bRequest;
 | 
				
			||||||
 | 
					    usbWord_t   wValue;
 | 
				
			||||||
 | 
					    usbWord_t   wIndex;
 | 
				
			||||||
 | 
					    usbWord_t   wLength;
 | 
				
			||||||
 | 
					}usbRequest_t;
 | 
				
			||||||
 | 
					/* This structure matches the 8 byte setup request */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* bmRequestType field in USB setup:
 | 
				
			||||||
 | 
					 * d t t r r r r r, where
 | 
				
			||||||
 | 
					 * d ..... direction: 0=host->device, 1=device->host
 | 
				
			||||||
 | 
					 * t ..... type: 0=standard, 1=class, 2=vendor, 3=reserved
 | 
				
			||||||
 | 
					 * r ..... recipient: 0=device, 1=interface, 2=endpoint, 3=other
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB setup recipient values */
 | 
				
			||||||
 | 
					#define USBRQ_RCPT_MASK         0x1f
 | 
				
			||||||
 | 
					#define USBRQ_RCPT_DEVICE       0
 | 
				
			||||||
 | 
					#define USBRQ_RCPT_INTERFACE    1
 | 
				
			||||||
 | 
					#define USBRQ_RCPT_ENDPOINT     2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB request type values */
 | 
				
			||||||
 | 
					#define USBRQ_TYPE_MASK         0x60
 | 
				
			||||||
 | 
					#define USBRQ_TYPE_STANDARD     (0<<5)
 | 
				
			||||||
 | 
					#define USBRQ_TYPE_CLASS        (1<<5)
 | 
				
			||||||
 | 
					#define USBRQ_TYPE_VENDOR       (2<<5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB direction values: */
 | 
				
			||||||
 | 
					#define USBRQ_DIR_MASK              0x80
 | 
				
			||||||
 | 
					#define USBRQ_DIR_HOST_TO_DEVICE    (0<<7)
 | 
				
			||||||
 | 
					#define USBRQ_DIR_DEVICE_TO_HOST    (1<<7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB Standard Requests */
 | 
				
			||||||
 | 
					#define USBRQ_GET_STATUS        0
 | 
				
			||||||
 | 
					#define USBRQ_CLEAR_FEATURE     1
 | 
				
			||||||
 | 
					#define USBRQ_SET_FEATURE       3
 | 
				
			||||||
 | 
					#define USBRQ_SET_ADDRESS       5
 | 
				
			||||||
 | 
					#define USBRQ_GET_DESCRIPTOR    6
 | 
				
			||||||
 | 
					#define USBRQ_SET_DESCRIPTOR    7
 | 
				
			||||||
 | 
					#define USBRQ_GET_CONFIGURATION 8
 | 
				
			||||||
 | 
					#define USBRQ_SET_CONFIGURATION 9
 | 
				
			||||||
 | 
					#define USBRQ_GET_INTERFACE     10
 | 
				
			||||||
 | 
					#define USBRQ_SET_INTERFACE     11
 | 
				
			||||||
 | 
					#define USBRQ_SYNCH_FRAME       12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB descriptor constants */
 | 
				
			||||||
 | 
					#define USBDESCR_DEVICE         1
 | 
				
			||||||
 | 
					#define USBDESCR_CONFIG         2
 | 
				
			||||||
 | 
					#define USBDESCR_STRING         3
 | 
				
			||||||
 | 
					#define USBDESCR_INTERFACE      4
 | 
				
			||||||
 | 
					#define USBDESCR_ENDPOINT       5
 | 
				
			||||||
 | 
					#define USBDESCR_HID            0x21
 | 
				
			||||||
 | 
					#define USBDESCR_HID_REPORT     0x22
 | 
				
			||||||
 | 
					#define USBDESCR_HID_PHYS       0x23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USBATTR_BUSPOWER        0x80
 | 
				
			||||||
 | 
					#define USBATTR_SELFPOWER       0x40
 | 
				
			||||||
 | 
					#define USBATTR_REMOTEWAKE      0x20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* USB HID Requests */
 | 
				
			||||||
 | 
					#define USBRQ_HID_GET_REPORT    0x01
 | 
				
			||||||
 | 
					#define USBRQ_HID_GET_IDLE      0x02
 | 
				
			||||||
 | 
					#define USBRQ_HID_GET_PROTOCOL  0x03
 | 
				
			||||||
 | 
					#define USBRQ_HID_SET_REPORT    0x09
 | 
				
			||||||
 | 
					#define USBRQ_HID_SET_IDLE      0x0a
 | 
				
			||||||
 | 
					#define USBRQ_HID_SET_PROTOCOL  0x0b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ------------------------------------------------------------------------- */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __usbdrv_h_included__ */
 | 
				
			||||||
							
								
								
									
										784
									
								
								firmware/usbdrv/usbdrvasm.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										784
									
								
								firmware/usbdrv/usbdrvasm.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,784 @@
 | 
				
			|||||||
 | 
					/* Name: usbdrvasm.S
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2004-12-29
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: usbdrvasm.S,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					This module implements the assembler part of the USB driver. See usbdrv.h
 | 
				
			||||||
 | 
					for a description of the entire driver.
 | 
				
			||||||
 | 
					Since almost all of this code is timing critical, don't change unless you
 | 
				
			||||||
 | 
					really know what you are doing! Many parts require not only a maximum number
 | 
				
			||||||
 | 
					of CPU cycles, but even an exact number of cycles!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Timing constraints according to spec (in bit times):
 | 
				
			||||||
 | 
					timing subject                                      min max    CPUcycles
 | 
				
			||||||
 | 
					---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2   16     16-128
 | 
				
			||||||
 | 
					EOP of IN to sync pattern of DATA0 (rx, then tx)    2   7.5    16-60
 | 
				
			||||||
 | 
					DATAx (rx) to ACK/NAK/STALL (tx)                    2   7.5    16-60
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "iarcompat.h"
 | 
				
			||||||
 | 
					#ifndef __IAR_SYSTEMS_ASM__
 | 
				
			||||||
 | 
					    /* configs for io.h */
 | 
				
			||||||
 | 
					#   define __SFR_OFFSET 0
 | 
				
			||||||
 | 
					#   define _VECTOR(N)   __vector_ ## N   /* io.h does not define this for asm */
 | 
				
			||||||
 | 
					#   include <avr/io.h> /* for CPU I/O register definitions and vectors */
 | 
				
			||||||
 | 
					#endif  /* __IAR_SYSTEMS_ASM__ */
 | 
				
			||||||
 | 
					#include "usbdrv.h" /* for common defs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* register names */
 | 
				
			||||||
 | 
					#define x1      r16
 | 
				
			||||||
 | 
					#define x2      r17
 | 
				
			||||||
 | 
					#define shift   r18
 | 
				
			||||||
 | 
					#define cnt     r19
 | 
				
			||||||
 | 
					#define x3      r20
 | 
				
			||||||
 | 
					#define x4      r21
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Some assembler dependent definitions and declarations: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __IAR_SYSTEMS_ASM__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   define nop2     rjmp    $+2 /* jump to next instruction */
 | 
				
			||||||
 | 
					#   define XL       r26
 | 
				
			||||||
 | 
					#   define XH       r27
 | 
				
			||||||
 | 
					#   define YL       r28
 | 
				
			||||||
 | 
					#   define YH       r29
 | 
				
			||||||
 | 
					#   define ZL       r30
 | 
				
			||||||
 | 
					#   define ZH       r31
 | 
				
			||||||
 | 
					#   define lo8(x)   LOW(x)
 | 
				
			||||||
 | 
					#   define hi8(x)   ((x)>>8)    /* not HIGH to allow XLINK to make a proper range check */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extern  usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBuf
 | 
				
			||||||
 | 
					    extern  usbCurrentTok, usbRxLen, usbRxToken, usbAppBuf, usbTxLen
 | 
				
			||||||
 | 
					    extern  usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3
 | 
				
			||||||
 | 
					    public  usbCrc16
 | 
				
			||||||
 | 
					    public  usbCrc16Append
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    COMMON  INTVEC
 | 
				
			||||||
 | 
					    ORG     INT0_vect
 | 
				
			||||||
 | 
					    rjmp    SIG_INTERRUPT0
 | 
				
			||||||
 | 
					    RSEG    CODE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* __IAR_SYSTEMS_ASM__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   define nop2     rjmp    .+0 /* jump to next instruction */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .text
 | 
				
			||||||
 | 
					    .global SIG_INTERRUPT0
 | 
				
			||||||
 | 
					    .type   SIG_INTERRUPT0, @function
 | 
				
			||||||
 | 
					    .global usbCrc16
 | 
				
			||||||
 | 
					    .global usbCrc16Append
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __IAR_SYSTEMS_ASM__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SIG_INTERRUPT0:
 | 
				
			||||||
 | 
					;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
 | 
				
			||||||
 | 
					;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
 | 
				
			||||||
 | 
					;max allowable interrupt latency: 32 cycles -> max 25 cycles interrupt disable
 | 
				
			||||||
 | 
					;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes
 | 
				
			||||||
 | 
					usbInterrupt:
 | 
				
			||||||
 | 
					;order of registers pushed:
 | 
				
			||||||
 | 
					;x1, SREG, x2, cnt, shift, [YH, YL, x3]
 | 
				
			||||||
 | 
					    push    x1              ;2  push only what is necessary to sync with edge ASAP
 | 
				
			||||||
 | 
					    in      x1, SREG        ;1
 | 
				
			||||||
 | 
					    push    x1              ;2
 | 
				
			||||||
 | 
					;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
 | 
				
			||||||
 | 
					;sync up with J to K edge during sync pattern -- use fastest possible loops
 | 
				
			||||||
 | 
					;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
 | 
				
			||||||
 | 
					#if !USB_CFG_SAMPLE_EXACT
 | 
				
			||||||
 | 
					    ldi     x1, 5           ;1 setup a timeout for waitForK
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					waitForJ:
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS ;1 wait for D- == 1
 | 
				
			||||||
 | 
					    rjmp    waitForJ        ;2
 | 
				
			||||||
 | 
					#if USB_CFG_SAMPLE_EXACT
 | 
				
			||||||
 | 
					;The following code represents the unrolled loop in the else branch. It
 | 
				
			||||||
 | 
					;results in a sampling window of 1/4 bit which meets the spec.
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS
 | 
				
			||||||
 | 
					    rjmp    foundK
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS
 | 
				
			||||||
 | 
					    rjmp    foundK
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS
 | 
				
			||||||
 | 
					    rjmp    foundK
 | 
				
			||||||
 | 
					    nop
 | 
				
			||||||
 | 
					    nop2
 | 
				
			||||||
 | 
					foundK:
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					waitForK:
 | 
				
			||||||
 | 
					    dec     x1              ;1
 | 
				
			||||||
 | 
					    sbic    USBIN, USBMINUS ;1 wait for D- == 0
 | 
				
			||||||
 | 
					    brne    waitForK        ;2
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					;{2, 6} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
 | 
				
			||||||
 | 
					;we have 1 bit time for setup purposes, then sample again:
 | 
				
			||||||
 | 
					    push    x2              ;2
 | 
				
			||||||
 | 
					    push    cnt             ;2
 | 
				
			||||||
 | 
					    push    shift           ;2
 | 
				
			||||||
 | 
					shortcutEntry:
 | 
				
			||||||
 | 
					    ldi     cnt, 1          ;1 pre-init bit counter (-1 because no dec follows, -1 because 1 bit already sampled)
 | 
				
			||||||
 | 
					    ldi     x2, 1<<USB_CFG_DPLUS_BIT    ;1 -> 8   edge sync ended with D- == 0
 | 
				
			||||||
 | 
					;now wait until SYNC byte is over. Wait for either 2 bits low (success) or 2 bits high (failure)
 | 
				
			||||||
 | 
					waitNoChange:
 | 
				
			||||||
 | 
					    in      x1, USBIN       ;1 <-- sample, timing: edge + {2, 6} cycles
 | 
				
			||||||
 | 
					    eor     x2, x1          ;1
 | 
				
			||||||
 | 
					    sbrc    x2, USBMINUS    ;1 | 2
 | 
				
			||||||
 | 
					    ldi     cnt, 2          ;1 | 0 cnt = numBits - 1 (because dec follows)
 | 
				
			||||||
 | 
					    mov     x2, x1          ;1
 | 
				
			||||||
 | 
					    dec     cnt             ;1
 | 
				
			||||||
 | 
					    brne    waitNoChange    ;2 | 1
 | 
				
			||||||
 | 
					    sbrc    x1, USBMINUS    ;2
 | 
				
			||||||
 | 
					    rjmp    sofError        ;0 two consecutive "1" bits -> framing error
 | 
				
			||||||
 | 
					;start reading data, but don't check for bitstuffing because these are the
 | 
				
			||||||
 | 
					;first bits. Use the cycles for initialization instead. Note that we read and
 | 
				
			||||||
 | 
					;store the binary complement of the data stream because eor results in 1 for
 | 
				
			||||||
 | 
					;a change and 0 for no change.
 | 
				
			||||||
 | 
					    in      x1, USBIN       ;1 <-- sample bit 0, timing: edge + {3, 7} cycles
 | 
				
			||||||
 | 
					    eor     x2, x1          ;1
 | 
				
			||||||
 | 
					    ldi     shift, 0x00     ;1 prepare for bitstuff check later on in loop
 | 
				
			||||||
 | 
					    bst     x2, USBMINUS    ;1
 | 
				
			||||||
 | 
					    bld     shift, 0        ;1
 | 
				
			||||||
 | 
					    push    YH              ;2 -> 7
 | 
				
			||||||
 | 
					    in      x2, USBIN       ;1 <-- sample bit 1, timing: edge + {2, 6} cycles
 | 
				
			||||||
 | 
					    eor     x1, x2          ;1
 | 
				
			||||||
 | 
					    bst     x1, USBMINUS    ;1
 | 
				
			||||||
 | 
					    bld     shift, 1        ;1
 | 
				
			||||||
 | 
					    push    YL              ;2
 | 
				
			||||||
 | 
					    lds     YL, usbInputBuf ;2 -> 8
 | 
				
			||||||
 | 
					    in      x1, USBIN       ;1 <-- sample bit 2, timing: edge + {2, 6} cycles
 | 
				
			||||||
 | 
					    eor     x2, x1          ;1
 | 
				
			||||||
 | 
					    bst     x2, USBMINUS    ;1
 | 
				
			||||||
 | 
					    bld     shift, 2        ;1
 | 
				
			||||||
 | 
					    ldi     cnt, USB_BUFSIZE;1
 | 
				
			||||||
 | 
					    ldi     YH, hi8(usbRxBuf);1 assume that usbRxBuf does not cross a page
 | 
				
			||||||
 | 
					    push    x3              ;2 -> 8
 | 
				
			||||||
 | 
					    in      x2, USBIN       ;1 <-- sample bit 3, timing: edge + {2, 6} cycles
 | 
				
			||||||
 | 
					    eor     x1, x2          ;1
 | 
				
			||||||
 | 
					    bst     x1, USBMINUS    ;1
 | 
				
			||||||
 | 
					    bld     shift, 3        ;1
 | 
				
			||||||
 | 
					    ser     x3              ;1
 | 
				
			||||||
 | 
					    nop                     ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit4          ;2 -> 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shortcutToStart:            ;{,43} into next frame: max 5.5 sync bits missed
 | 
				
			||||||
 | 
					#if !USB_CFG_SAMPLE_EXACT
 | 
				
			||||||
 | 
					    ldi     x1, 5           ;2 setup timeout
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					waitForJ1:
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS ;1 wait for D- == 1
 | 
				
			||||||
 | 
					    rjmp    waitForJ1       ;2
 | 
				
			||||||
 | 
					#if USB_CFG_SAMPLE_EXACT
 | 
				
			||||||
 | 
					;The following code represents the unrolled loop in the else branch. It
 | 
				
			||||||
 | 
					;results in a sampling window of 1/4 bit which meets the spec.
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS
 | 
				
			||||||
 | 
					    rjmp    foundK1
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS
 | 
				
			||||||
 | 
					    rjmp    foundK1
 | 
				
			||||||
 | 
					    sbis    USBIN, USBMINUS
 | 
				
			||||||
 | 
					    rjmp    foundK1
 | 
				
			||||||
 | 
					    nop
 | 
				
			||||||
 | 
					    nop2
 | 
				
			||||||
 | 
					foundK1:
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					waitForK1:
 | 
				
			||||||
 | 
					    dec     x1              ;1
 | 
				
			||||||
 | 
					    sbic    USBIN, USBMINUS ;1 wait for D- == 0
 | 
				
			||||||
 | 
					    brne    waitForK1       ;2
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    pop     YH              ;2 correct stack alignment
 | 
				
			||||||
 | 
					    nop2                    ;2 delay for the same time as the pushes in the original code
 | 
				
			||||||
 | 
					    rjmp    shortcutEntry   ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; ################# receiver loop #################
 | 
				
			||||||
 | 
					; extra jobs done during bit interval:
 | 
				
			||||||
 | 
					; bit 6:    se0 check
 | 
				
			||||||
 | 
					; bit 7:    or, store, clear
 | 
				
			||||||
 | 
					; bit 0:    recover from delay  [SE0 is unreliable here due to bit dribbling in hubs]
 | 
				
			||||||
 | 
					; bit 1:    se0 check
 | 
				
			||||||
 | 
					; bit 2:    se0 check
 | 
				
			||||||
 | 
					; bit 3:    overflow check
 | 
				
			||||||
 | 
					; bit 4:    se0 check
 | 
				
			||||||
 | 
					; bit 5:    rjmp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; stuffed* helpers have the functionality of a subroutine, but we can't afford
 | 
				
			||||||
 | 
					; the overhead of a call. We therefore need a separate routine for each caller
 | 
				
			||||||
 | 
					; which jumps back appropriately.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed5:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x2, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0a        ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x20   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x20 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit6      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed6:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0a        ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x40   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x40 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit7      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; This is somewhat special because it has to compensate for the delay in bit 7
 | 
				
			||||||
 | 
					stuffed7:               ;1 for branch taken
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1 already sampled by caller
 | 
				
			||||||
 | 
					    breq    se0a        ;1
 | 
				
			||||||
 | 
					    mov     x2, x1      ;1 ensure correct NRZI sequence
 | 
				
			||||||
 | 
					    ori     shift, 0x80 ;1 no need to set reconstruction in x3: shift has already been used
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample bit 0
 | 
				
			||||||
 | 
					    rjmp    unstuffed7  ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed0:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0a        ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x01   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x01 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit1      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;-----------------------------
 | 
				
			||||||
 | 
					rxLoop:
 | 
				
			||||||
 | 
					    breq    stuffed5    ;1
 | 
				
			||||||
 | 
					rxbit6:
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample bit 6
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0a        ;1
 | 
				
			||||||
 | 
					    eor     x2, x1      ;1
 | 
				
			||||||
 | 
					    bst     x2, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 6    ;1
 | 
				
			||||||
 | 
					    cpi     shift, 0x02 ;1
 | 
				
			||||||
 | 
					    brlo    stuffed6    ;1
 | 
				
			||||||
 | 
					rxbit7:
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample bit 7
 | 
				
			||||||
 | 
					    eor     x1, x2      ;1
 | 
				
			||||||
 | 
					    bst     x1, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 7    ;1
 | 
				
			||||||
 | 
					    eor     x3, shift   ;1 x3 is 0 at bit locations we changed, 1 at others
 | 
				
			||||||
 | 
					    st      y+, x3      ;2 the eor above reconstructed modified bits and inverted rx data
 | 
				
			||||||
 | 
					    ser     x3          ;1
 | 
				
			||||||
 | 
					rxbit0:
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample bit 0
 | 
				
			||||||
 | 
					    cpi     shift, 0x04 ;1
 | 
				
			||||||
 | 
					    brlo    stuffed7    ;1
 | 
				
			||||||
 | 
					unstuffed7:
 | 
				
			||||||
 | 
					    eor     x2, x1      ;1
 | 
				
			||||||
 | 
					    bst     x2, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 0    ;1
 | 
				
			||||||
 | 
					    andi    shift, 0xf9 ;1
 | 
				
			||||||
 | 
					    breq    stuffed0    ;1
 | 
				
			||||||
 | 
					rxbit1:
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample bit 1
 | 
				
			||||||
 | 
					    andi    x2, USBMASK ;1
 | 
				
			||||||
 | 
					se0a:                   ; enlarge jump range to SE0
 | 
				
			||||||
 | 
					    breq    se0         ;1 check for SE0 more often close to start of byte
 | 
				
			||||||
 | 
					    eor     x1, x2      ;1
 | 
				
			||||||
 | 
					    bst     x1, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 1    ;1
 | 
				
			||||||
 | 
					    andi    shift, 0xf3 ;1
 | 
				
			||||||
 | 
					    breq    stuffed1    ;1
 | 
				
			||||||
 | 
					rxbit2:
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample bit 2
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0         ;1
 | 
				
			||||||
 | 
					    eor     x2, x1      ;1
 | 
				
			||||||
 | 
					    bst     x2, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 2    ;1
 | 
				
			||||||
 | 
					    andi    shift, 0xe7 ;1
 | 
				
			||||||
 | 
					    breq    stuffed2    ;1
 | 
				
			||||||
 | 
					rxbit3:
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample bit 3
 | 
				
			||||||
 | 
					    eor     x1, x2      ;1
 | 
				
			||||||
 | 
					    bst     x1, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 3    ;1
 | 
				
			||||||
 | 
					    dec     cnt         ;1  check for buffer overflow
 | 
				
			||||||
 | 
					    breq    overflow    ;1
 | 
				
			||||||
 | 
					    andi    shift, 0xcf ;1
 | 
				
			||||||
 | 
					    breq    stuffed3    ;1
 | 
				
			||||||
 | 
					rxbit4:
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample bit 4
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0         ;1
 | 
				
			||||||
 | 
					    eor     x2, x1      ;1
 | 
				
			||||||
 | 
					    bst     x2, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 4    ;1
 | 
				
			||||||
 | 
					    andi    shift, 0x9f ;1
 | 
				
			||||||
 | 
					    breq    stuffed4    ;1
 | 
				
			||||||
 | 
					rxbit5:
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample bit 5
 | 
				
			||||||
 | 
					    eor     x1, x2      ;1
 | 
				
			||||||
 | 
					    bst     x1, USBMINUS;1
 | 
				
			||||||
 | 
					    bld     shift, 5    ;1
 | 
				
			||||||
 | 
					    andi    shift, 0x3f ;1
 | 
				
			||||||
 | 
					    rjmp    rxLoop      ;2
 | 
				
			||||||
 | 
					;-----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed1:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x2, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0         ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x02   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x02 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit2      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed2:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0         ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x04   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x04 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit3      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed3:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x2, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x2, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0         ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x08   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x08 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit4      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stuffed4:               ;1 for branch taken
 | 
				
			||||||
 | 
					    in      x1, USBIN   ;1 <-- sample @ +1
 | 
				
			||||||
 | 
					    andi    x1, USBMASK ;1
 | 
				
			||||||
 | 
					    breq    se0         ;1
 | 
				
			||||||
 | 
					    andi    x3, ~0x10   ;1
 | 
				
			||||||
 | 
					    ori     shift, 0x10 ;1
 | 
				
			||||||
 | 
					    rjmp    rxbit5      ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;################ end receiver loop ###############
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					overflow:                   ; ignore package if buffer overflow
 | 
				
			||||||
 | 
					    rjmp    rxDoReturn      ; enlarge jump range
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;This is the only non-error exit point for the software receiver loop
 | 
				
			||||||
 | 
					;{4, 20} cycles after start of SE0, typically {10, 18} after SE0 start = {-6, 2} from end of SE0
 | 
				
			||||||
 | 
					;next sync starts {16,} cycles after SE0 -> worst case start: +4 from next sync start
 | 
				
			||||||
 | 
					;we don't check any CRCs here because there is no time left.
 | 
				
			||||||
 | 
					se0:                            ;{-6, 2} from end of SE0 / {,4} into next frame
 | 
				
			||||||
 | 
					    mov     cnt, YL             ;1 assume buffer in lower 256 bytes of memory
 | 
				
			||||||
 | 
					    lds     YL, usbInputBuf     ;2 reposition to buffer start
 | 
				
			||||||
 | 
					    sub     cnt, YL             ;1 length of message
 | 
				
			||||||
 | 
					    ldi     x1, 1<<USB_INTR_PENDING_BIT ;1
 | 
				
			||||||
 | 
					    cpi     cnt, 3              ;1
 | 
				
			||||||
 | 
					    out     USB_INTR_PENDING, x1;1 clear pending intr and check flag later. SE0 must be over. {,10} into next frame
 | 
				
			||||||
 | 
					    brlo    rxDoReturn          ;1 ensure valid packet size, ignore others
 | 
				
			||||||
 | 
					    ld      x1, y               ;2 PID
 | 
				
			||||||
 | 
					    ldd     x2, y+1             ;2 ADDR + 1 bit endpoint number
 | 
				
			||||||
 | 
					    mov     x3, x2              ;1 store for endpoint number
 | 
				
			||||||
 | 
					    andi    x2, 0x7f            ;1 mask endpoint number bit
 | 
				
			||||||
 | 
					    lds     shift, usbDeviceAddr;2
 | 
				
			||||||
 | 
					    cpi     x1, USBPID_SETUP    ;1
 | 
				
			||||||
 | 
					    breq    isSetupOrOut        ;2 -> 19 = {13, 21} from SE0 end
 | 
				
			||||||
 | 
					    cpi     x1, USBPID_OUT      ;1
 | 
				
			||||||
 | 
					    breq    isSetupOrOut        ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame
 | 
				
			||||||
 | 
					    cpi     x1, USBPID_IN       ;1
 | 
				
			||||||
 | 
					    breq    handleIn            ;1
 | 
				
			||||||
 | 
					#define USB_DATA_MASK   ~(USBPID_DATA0 ^ USBPID_DATA1)
 | 
				
			||||||
 | 
					    andi    x1, USB_DATA_MASK   ;1
 | 
				
			||||||
 | 
					    cpi     x1, USBPID_DATA0 & USB_DATA_MASK ;1
 | 
				
			||||||
 | 
					    brne    rxDoReturn          ;1 not a data PID -- ignore
 | 
				
			||||||
 | 
					isData:
 | 
				
			||||||
 | 
					    lds     x2, usbCurrentTok   ;2
 | 
				
			||||||
 | 
					    tst     x2                  ;1
 | 
				
			||||||
 | 
					    breq    rxDoReturn          ;1 for other device or spontaneous data -- ignore
 | 
				
			||||||
 | 
					    lds     x1, usbRxLen        ;2
 | 
				
			||||||
 | 
					    cpi     x1, 0               ;1
 | 
				
			||||||
 | 
					    brne    sendNakAndReti      ;1 no buffer space available / {30, 38} from SE0 end
 | 
				
			||||||
 | 
					; 2006-03-11: The following two lines fix a problem where the device was not
 | 
				
			||||||
 | 
					; recognized if usbPoll() was called less frequently than once every 4 ms.
 | 
				
			||||||
 | 
					    cpi     cnt, 4              ;1 zero sized data packets are status phase only -- ignore and ack
 | 
				
			||||||
 | 
					    brmi    sendAckAndReti      ;1 keep rx buffer clean -- we must not NAK next SETUP
 | 
				
			||||||
 | 
					    sts     usbRxLen, cnt       ;2 store received data, swap buffers
 | 
				
			||||||
 | 
					    sts     usbRxToken, x2      ;2
 | 
				
			||||||
 | 
					    lds     x1, usbAppBuf       ;2
 | 
				
			||||||
 | 
					    sts     usbAppBuf, YL       ;2
 | 
				
			||||||
 | 
					    sts     usbInputBuf, x1     ;2 buffers now swapped
 | 
				
			||||||
 | 
					    rjmp    sendAckAndReti      ;2 -> {43, 51} from SE0 end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handleIn:                       ; {18, 26} from SE0 end
 | 
				
			||||||
 | 
					    cp      x2, shift           ;1 shift contains our device addr
 | 
				
			||||||
 | 
					    brne    rxDoReturn          ;1 other device
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT
 | 
				
			||||||
 | 
					    sbrc    x3, 7               ;2 x3 contains addr + endpoint
 | 
				
			||||||
 | 
					    rjmp    handleIn1           ;0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    lds     cnt, usbTxLen       ;2
 | 
				
			||||||
 | 
					    sbrc    cnt, 4              ;2
 | 
				
			||||||
 | 
					    rjmp    sendCntAndReti      ;0 -> {27, 35} from SE0 end
 | 
				
			||||||
 | 
					    ldi     x1, USBPID_NAK      ;1
 | 
				
			||||||
 | 
					    sts     usbTxLen, x1        ;2 buffer is now free
 | 
				
			||||||
 | 
					    ldi     YL, lo8(usbTxBuf)   ;1
 | 
				
			||||||
 | 
					    ldi     YH, hi8(usbTxBuf)   ;1
 | 
				
			||||||
 | 
					    rjmp    usbSendAndReti      ;2 -> {34, 43} from SE0 end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; Comment about when to set usbTxLen to USBPID_NAK:
 | 
				
			||||||
 | 
					; We should set it back when we receive the ACK from the host. This would
 | 
				
			||||||
 | 
					; be simple to implement: One static variable which stores whether the last
 | 
				
			||||||
 | 
					; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
 | 
				
			||||||
 | 
					; ACK. However, we set it back immediately when we send the package,
 | 
				
			||||||
 | 
					; assuming that no error occurs and the host sends an ACK. We save one byte
 | 
				
			||||||
 | 
					; RAM this way and avoid potential problems with endless retries. The rest of
 | 
				
			||||||
 | 
					; the driver assumes error-free transfers anyway.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					otherOutOrSetup:
 | 
				
			||||||
 | 
					    clr     x1
 | 
				
			||||||
 | 
					    sts     usbCurrentTok, x1
 | 
				
			||||||
 | 
					rxDoReturn:
 | 
				
			||||||
 | 
					    pop     x3                  ;2
 | 
				
			||||||
 | 
					    pop     YL                  ;2
 | 
				
			||||||
 | 
					    pop     YH                  ;2
 | 
				
			||||||
 | 
					    rjmp    sofError            ;2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					isSetupOrOut:                   ; we must be fast here -- a data package may follow / {,24} into next frame
 | 
				
			||||||
 | 
					    cp      x2, shift           ;1 shift contains our device addr
 | 
				
			||||||
 | 
					    brne    otherOutOrSetup     ;1 other device -- ignore
 | 
				
			||||||
 | 
					#if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we need second OUT endpoint, store endpoint address */
 | 
				
			||||||
 | 
					    andi    x1, 0x7f            ;1 mask out MSb in token
 | 
				
			||||||
 | 
					    andi    x3, 0x80            ;1 mask out all but endpoint address
 | 
				
			||||||
 | 
					    or      x1, x3              ;1 merge endpoint into currentToken
 | 
				
			||||||
 | 
					    sts     usbCurrentTok, x1   ;2
 | 
				
			||||||
 | 
					    brmi    dontResetEP0        ;1 endpoint 1 -> don't reset endpoint 0 input
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    sts     usbCurrentTok, x1   ;2
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					;A transmission can still have data in the output buffer while we receive a
 | 
				
			||||||
 | 
					;SETUP package with an IN phase. To avoid that the old data is sent as a reply,
 | 
				
			||||||
 | 
					;we abort transmission. We don't need to reset usbMsgLen because it is used
 | 
				
			||||||
 | 
					;from the main loop only where the setup is processed anyway.
 | 
				
			||||||
 | 
					    ldi     x1, USBPID_NAK      ;1
 | 
				
			||||||
 | 
					    sts     usbTxLen, x1        ;2 abort transmission
 | 
				
			||||||
 | 
					dontResetEP0:
 | 
				
			||||||
 | 
					    pop     x3                  ;2
 | 
				
			||||||
 | 
					    pop     YL                  ;2
 | 
				
			||||||
 | 
					    in      x1, USB_INTR_PENDING;1
 | 
				
			||||||
 | 
					    sbrc    x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame
 | 
				
			||||||
 | 
					    rjmp    shortcutToStart     ;2 save the pops and pushes -- a new interrupt is aready pending
 | 
				
			||||||
 | 
					;If the jump above was not taken, we can be at {,2} into the next frame here
 | 
				
			||||||
 | 
					    pop     YH                  ;2
 | 
				
			||||||
 | 
					txDoReturn:
 | 
				
			||||||
 | 
					sofError:                       ; error in start of frame -- ignore frame
 | 
				
			||||||
 | 
					    ldi     x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag
 | 
				
			||||||
 | 
					    out     USB_INTR_PENDING, x1;1
 | 
				
			||||||
 | 
					    pop     shift               ;2
 | 
				
			||||||
 | 
					    pop     cnt                 ;2
 | 
				
			||||||
 | 
					    pop     x2                  ;2
 | 
				
			||||||
 | 
					    pop     x1                  ;2
 | 
				
			||||||
 | 
					    out     SREG, x1            ;1
 | 
				
			||||||
 | 
					    pop     x1                  ;2
 | 
				
			||||||
 | 
					    reti                        ;4 -> {,21} into next frame -> up to 3 sync bits missed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sendCntAndReti:                 ; 19 cycles until SOP
 | 
				
			||||||
 | 
					    mov     x3, cnt             ;1
 | 
				
			||||||
 | 
					    rjmp    usbSendX3           ;2
 | 
				
			||||||
 | 
					sendNakAndReti:                 ; 19 cycles until SOP
 | 
				
			||||||
 | 
					    ldi     x3, USBPID_NAK      ;1
 | 
				
			||||||
 | 
					    rjmp    usbSendX3           ;2
 | 
				
			||||||
 | 
					sendAckAndReti:                 ; 17 cycles until SOP
 | 
				
			||||||
 | 
					    ldi     x3, USBPID_ACK      ;1
 | 
				
			||||||
 | 
					usbSendX3:
 | 
				
			||||||
 | 
					    ldi     YL, 20              ;1 'x3' is R20
 | 
				
			||||||
 | 
					    ldi     YH, 0               ;1
 | 
				
			||||||
 | 
					    ldi     cnt, 2              ;1
 | 
				
			||||||
 | 
					;;;;rjmp    usbSendAndReti      fallthrough
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; USB spec says:
 | 
				
			||||||
 | 
					; idle = J
 | 
				
			||||||
 | 
					; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
 | 
				
			||||||
 | 
					; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
 | 
				
			||||||
 | 
					; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;usbSend:
 | 
				
			||||||
 | 
					;pointer to data in 'Y'
 | 
				
			||||||
 | 
					;number of bytes in 'cnt' -- including sync byte
 | 
				
			||||||
 | 
					;uses: x1...x4, shift, cnt, Y
 | 
				
			||||||
 | 
					usbSendAndReti:             ; SOP starts 13 cycles after call
 | 
				
			||||||
 | 
					    push    x4              ;2
 | 
				
			||||||
 | 
					    ldi     x4, USBMASK     ;1 exor mask
 | 
				
			||||||
 | 
					    sbi     USBOUT, USBMINUS;1 prepare idle state; D+ and D- must have been 0 (no pullups)
 | 
				
			||||||
 | 
					    in      x1, USBOUT      ;1 port mirror for tx loop
 | 
				
			||||||
 | 
					    sbi     USBDDR, USBMINUS;1
 | 
				
			||||||
 | 
					    sbi     USBDDR, USBPLUS ;1 set D+ and D- to output: acquire bus
 | 
				
			||||||
 | 
					; need not init x2 (bitstuff history) because sync starts with 0
 | 
				
			||||||
 | 
					    ldi     shift, 0x80     ;1 sync byte is first byte sent
 | 
				
			||||||
 | 
					    rjmp    txLoop          ;2 -> 13 + 3 = 16 cycles until SOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT    /* placed here due to relative jump range */
 | 
				
			||||||
 | 
					handleIn1:                  ;{23, 31} from SE0
 | 
				
			||||||
 | 
					    ldi     x1, USBPID_NAK  ;1
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
 | 
				
			||||||
 | 
					    ldd     x2, y+2         ;2
 | 
				
			||||||
 | 
					    sbrc    x2, 0           ;2 1
 | 
				
			||||||
 | 
					    rjmp    handleIn3       ;0 2
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    lds     cnt, usbTxLen1  ;2
 | 
				
			||||||
 | 
					    sbrc    cnt, 4          ;2
 | 
				
			||||||
 | 
					    rjmp    sendCntAndReti  ;0
 | 
				
			||||||
 | 
					    sts     usbTxLen1, x1   ;2
 | 
				
			||||||
 | 
					    ldi     YL, lo8(usbTxBuf1);1
 | 
				
			||||||
 | 
					    ldi     YH, hi8(usbTxBuf1);1
 | 
				
			||||||
 | 
					    rjmp    usbSendAndReti  ;2 -> arrives at usbSendAndReti {34, 42} from SE0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
				
			||||||
 | 
					handleIn3:
 | 
				
			||||||
 | 
					    lds     cnt, usbTxLen3  ;2
 | 
				
			||||||
 | 
					    sbrc    cnt, 4          ;2
 | 
				
			||||||
 | 
					    rjmp    sendCntAndReti  ;0
 | 
				
			||||||
 | 
					    sts     usbTxLen3, x1   ;2
 | 
				
			||||||
 | 
					    ldi     YL, lo8(usbTxBuf3);1
 | 
				
			||||||
 | 
					    ldi     YH, hi8(usbTxBuf3);1
 | 
				
			||||||
 | 
					    rjmp    usbSendAndReti  ;2 -> arrives at usbSendAndReti {39, 47} from SE0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bitstuff0:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    rjmp    didStuff0       ;2 branch back 2 cycles earlier
 | 
				
			||||||
 | 
					bitstuff1:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    sec                     ;1 set carry so that brsh will not jump
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    rjmp    didStuff1       ;2 jump back 1 cycle earler
 | 
				
			||||||
 | 
					bitstuff2:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    rjmp    didStuff2       ;2 jump back 3 cycles earlier and do out
 | 
				
			||||||
 | 
					bitstuff3:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    rjmp    didStuff3       ;2 jump back earlier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					txLoop:
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					didStuff0:
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					    brsh    bitstuff0       ;1
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					didStuff1:
 | 
				
			||||||
 | 
					    brsh    bitstuff1       ;1
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					didStuff2:
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					    brsh    bitstuff2       ;1
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					didStuff3:
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    brsh    bitstuff3       ;1
 | 
				
			||||||
 | 
					    nop2                    ;2
 | 
				
			||||||
 | 
					    ld      x3, y+          ;2
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					didStuff4:
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					    brsh    bitstuff4       ;1
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					didStuff5:
 | 
				
			||||||
 | 
					    brsh    bitstuff5       ;1
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					didStuff6:
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					    brsh    bitstuff6       ;1
 | 
				
			||||||
 | 
					    sbrs    shift, 0        ;1
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ror     shift           ;1
 | 
				
			||||||
 | 
					    ror     x2              ;1
 | 
				
			||||||
 | 
					didStuff7:
 | 
				
			||||||
 | 
					    cpi     x2, 0xfc        ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    brsh    bitstuff7       ;1
 | 
				
			||||||
 | 
					    mov     shift, x3       ;1
 | 
				
			||||||
 | 
					    dec     cnt             ;1
 | 
				
			||||||
 | 
					    brne    txLoop          ;2 | 1
 | 
				
			||||||
 | 
					    cbr     x1, USBMASK     ;1 prepare SE0 [spec says EOP may be 15 to 18 cycles]
 | 
				
			||||||
 | 
					    pop     x4              ;2
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
 | 
				
			||||||
 | 
					    ldi     cnt, 2          ;| takes cnt * 3 cycles
 | 
				
			||||||
 | 
					se0Delay:                   ;|
 | 
				
			||||||
 | 
					    dec     cnt             ;|
 | 
				
			||||||
 | 
					    brne    se0Delay        ;| -> 2 * 3 = 6 cycles
 | 
				
			||||||
 | 
					;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
 | 
				
			||||||
 | 
					;set address only after data packet was sent, not after handshake
 | 
				
			||||||
 | 
					    lds     x2, usbNewDeviceAddr;2
 | 
				
			||||||
 | 
					    subi    YL, 20 + 2          ;1
 | 
				
			||||||
 | 
					    sbci    YH, 0               ;1
 | 
				
			||||||
 | 
					    breq    skipAddrAssign      ;2
 | 
				
			||||||
 | 
					    sts     usbDeviceAddr, x2   ;0  if not skipped: SE0 is one cycle longer
 | 
				
			||||||
 | 
					skipAddrAssign:
 | 
				
			||||||
 | 
					;end of usbDeviceAddress transfer
 | 
				
			||||||
 | 
					    ori     x1, USBIDLE     ;1
 | 
				
			||||||
 | 
					    in      x2, USBDDR      ;1
 | 
				
			||||||
 | 
					    cbr     x2, USBMASK     ;1 set both pins to input
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out J (idle) -- end of SE0 (EOP signal)
 | 
				
			||||||
 | 
					    cbr     x1, USBMASK     ;1 configure no pullup on both pins
 | 
				
			||||||
 | 
					    pop     x3              ;2
 | 
				
			||||||
 | 
					    pop     YL              ;2
 | 
				
			||||||
 | 
					    out     USBDDR, x2      ;1 <-- release bus now
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 set pullup state
 | 
				
			||||||
 | 
					    pop     YH              ;2
 | 
				
			||||||
 | 
					    rjmp    txDoReturn      ;2 [we want to jump to rxDoReturn, but this saves cycles]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bitstuff4:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    rjmp    didStuff4       ;2 jump back 2 cycles earlier
 | 
				
			||||||
 | 
					bitstuff5:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    sec                     ;1 set carry so that brsh is not taken
 | 
				
			||||||
 | 
					    out     USBOUT, x1      ;1 <-- out
 | 
				
			||||||
 | 
					    rjmp    didStuff5       ;2 jump back 1 cycle earlier
 | 
				
			||||||
 | 
					bitstuff6:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    rjmp    didStuff6       ;2 jump back 3 cycles earlier and do out there
 | 
				
			||||||
 | 
					bitstuff7:                  ;1 (for branch taken)
 | 
				
			||||||
 | 
					    eor     x1, x4          ;1
 | 
				
			||||||
 | 
					    ldi     x2, 0           ;1
 | 
				
			||||||
 | 
					    rjmp    didStuff7       ;2 jump back 4 cycles earlier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; ######################## utility functions ########################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __IAR_SYSTEMS_ASM__
 | 
				
			||||||
 | 
					/* Register assignments for usbCrc16 on IAR cc */
 | 
				
			||||||
 | 
					/* Calling conventions on IAR:
 | 
				
			||||||
 | 
					 * First parameter passed in r16/r17, second in r18/r19 and so on.
 | 
				
			||||||
 | 
					 * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
 | 
				
			||||||
 | 
					 * Result is passed in r16/r17
 | 
				
			||||||
 | 
					 * In case of the "tiny" memory model, pointers are only 8 bit with no
 | 
				
			||||||
 | 
					 * padding. We therefore pass argument 1 as "16 bit unsigned".
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RTMODEL "__rt_version", "3"
 | 
				
			||||||
 | 
					/* The line above will generate an error if cc calling conventions change.
 | 
				
			||||||
 | 
					 * The value "3" above is valid for IAR 4.10B/W32
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#   define argLen   r18 /* argument 2 */
 | 
				
			||||||
 | 
					#   define argPtrL  r16 /* argument 1 */
 | 
				
			||||||
 | 
					#   define argPtrH  r17 /* argument 1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   define resCrcL  r16 /* result */
 | 
				
			||||||
 | 
					#   define resCrcH  r17 /* result */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   define ptrL     ZL
 | 
				
			||||||
 | 
					#   define ptrH     ZH
 | 
				
			||||||
 | 
					#   define ptr      Z
 | 
				
			||||||
 | 
					#   define byte     r22
 | 
				
			||||||
 | 
					#   define bitCnt   r19
 | 
				
			||||||
 | 
					#   define polyL    r20
 | 
				
			||||||
 | 
					#   define polyH    r21
 | 
				
			||||||
 | 
					#   define scratch  r23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else  /* __IAR_SYSTEMS_ASM__ */ 
 | 
				
			||||||
 | 
					/* Register assignments for usbCrc16 on gcc */
 | 
				
			||||||
 | 
					/* Calling conventions on gcc:
 | 
				
			||||||
 | 
					 * First parameter passed in r24/r25, second in r22/23 and so on.
 | 
				
			||||||
 | 
					 * Callee must preserve r1-r17, r28/r29
 | 
				
			||||||
 | 
					 * Result is passed in r24/r25
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#   define argLen   r22 /* argument 2 */
 | 
				
			||||||
 | 
					#   define argPtrL  r24 /* argument 1 */
 | 
				
			||||||
 | 
					#   define argPtrH  r25 /* argument 1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   define resCrcL  r24 /* result */
 | 
				
			||||||
 | 
					#   define resCrcH  r25 /* result */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   define ptrL     XL
 | 
				
			||||||
 | 
					#   define ptrH     XH
 | 
				
			||||||
 | 
					#   define ptr      x
 | 
				
			||||||
 | 
					#   define byte     r18
 | 
				
			||||||
 | 
					#   define bitCnt   r19
 | 
				
			||||||
 | 
					#   define polyL    r20
 | 
				
			||||||
 | 
					#   define polyH    r21
 | 
				
			||||||
 | 
					#   define scratch  r23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; extern unsigned usbCrc16(unsigned char *data, unsigned char len);
 | 
				
			||||||
 | 
					; data: r24/25
 | 
				
			||||||
 | 
					; len: r22
 | 
				
			||||||
 | 
					; temp variables:
 | 
				
			||||||
 | 
					;   r18: data byte
 | 
				
			||||||
 | 
					;   r19: bit counter
 | 
				
			||||||
 | 
					;   r20/21: polynomial
 | 
				
			||||||
 | 
					;   r23: scratch
 | 
				
			||||||
 | 
					;   r24/25: crc-sum
 | 
				
			||||||
 | 
					;   r26/27=X: ptr
 | 
				
			||||||
 | 
					usbCrc16:
 | 
				
			||||||
 | 
					    mov     ptrL, argPtrL
 | 
				
			||||||
 | 
					    mov     ptrH, argPtrH
 | 
				
			||||||
 | 
					    ldi     resCrcL, 0xff
 | 
				
			||||||
 | 
					    ldi     resCrcH, 0xff
 | 
				
			||||||
 | 
					    ldi     polyL, lo8(0xa001)
 | 
				
			||||||
 | 
					    ldi     polyH, hi8(0xa001)
 | 
				
			||||||
 | 
					crcByteLoop:
 | 
				
			||||||
 | 
					    subi    argLen, 1
 | 
				
			||||||
 | 
					    brcs    crcReady
 | 
				
			||||||
 | 
					    ld      byte, ptr+
 | 
				
			||||||
 | 
					    ldi     bitCnt, 8
 | 
				
			||||||
 | 
					crcBitLoop:
 | 
				
			||||||
 | 
					    mov     scratch, byte
 | 
				
			||||||
 | 
					    eor     scratch, resCrcL
 | 
				
			||||||
 | 
					    lsr     resCrcH
 | 
				
			||||||
 | 
					    ror     resCrcL
 | 
				
			||||||
 | 
					    lsr     byte
 | 
				
			||||||
 | 
					    sbrs    scratch, 0
 | 
				
			||||||
 | 
					    rjmp    crcNoXor
 | 
				
			||||||
 | 
					    eor     resCrcL, polyL
 | 
				
			||||||
 | 
					    eor     resCrcH, polyH
 | 
				
			||||||
 | 
					crcNoXor:
 | 
				
			||||||
 | 
					    dec     bitCnt
 | 
				
			||||||
 | 
					    brne    crcBitLoop
 | 
				
			||||||
 | 
					    rjmp    crcByteLoop
 | 
				
			||||||
 | 
					crcReady:
 | 
				
			||||||
 | 
					    com     resCrcL
 | 
				
			||||||
 | 
					    com     resCrcH
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
 | 
				
			||||||
 | 
					usbCrc16Append:
 | 
				
			||||||
 | 
					    rcall   usbCrc16
 | 
				
			||||||
 | 
					    st      ptr+, resCrcL
 | 
				
			||||||
 | 
					    st      ptr+, resCrcH
 | 
				
			||||||
 | 
					    ret
 | 
				
			||||||
							
								
								
									
										21
									
								
								firmware/usbdrv/usbdrvasm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								firmware/usbdrv/usbdrvasm.asm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					/* Name: usbdrvasm.asm
 | 
				
			||||||
 | 
					 * Project: AVR USB driver
 | 
				
			||||||
 | 
					 * Author: Christian Starkjohann
 | 
				
			||||||
 | 
					 * Creation Date: 2006-03-01
 | 
				
			||||||
 | 
					 * Tabsize: 4
 | 
				
			||||||
 | 
					 * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
 | 
				
			||||||
 | 
					 * License: Proprietary, free under certain conditions. See Documentation.
 | 
				
			||||||
 | 
					 * This Revision: $Id: usbdrvasm.asm,v 1.1 2006/09/26 18:18:27 rschaten Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					General Description:
 | 
				
			||||||
 | 
					The IAR compiler/assembler system prefers assembler files with file extension
 | 
				
			||||||
 | 
					".asm". We simply provide this file as an alias for usbdrvasm.S.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thanks to Oleg Semyonov for his help with the IAR tools port!
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "usbdrvasm.S"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										1252
									
								
								usb-led-fader.doxygen
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1252
									
								
								usb-led-fader.doxygen
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user