First CVS-version
This commit is contained in:
		
							
								
								
									
										5
									
								
								Changelog.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Changelog.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					$Id: Changelog.txt,v 1.1 2007/01/02 21:30:39 rschaten Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Release 07010x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- initial release
 | 
				
			||||||
							
								
								
									
										340
									
								
								License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								License.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,340 @@
 | 
				
			|||||||
 | 
							    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
							       Version 2, June 1991
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					 Everyone is permitted to copy and distribute verbatim copies
 | 
				
			||||||
 | 
					 of this license document, but changing it is not allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    Preamble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The licenses for most software are designed to take away your
 | 
				
			||||||
 | 
					freedom to share and change it.  By contrast, the GNU General Public
 | 
				
			||||||
 | 
					License is intended to guarantee your freedom to share and change free
 | 
				
			||||||
 | 
					software--to make sure the software is free for all its users.  This
 | 
				
			||||||
 | 
					General Public License applies to most of the Free Software
 | 
				
			||||||
 | 
					Foundation's software and to any other program whose authors commit to
 | 
				
			||||||
 | 
					using it.  (Some other Free Software Foundation software is covered by
 | 
				
			||||||
 | 
					the GNU Library General Public License instead.)  You can apply it to
 | 
				
			||||||
 | 
					your programs, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  When we speak of free software, we are referring to freedom, not
 | 
				
			||||||
 | 
					price.  Our General Public Licenses are designed to make sure that you
 | 
				
			||||||
 | 
					have the freedom to distribute copies of free software (and charge for
 | 
				
			||||||
 | 
					this service if you wish), that you receive source code or can get it
 | 
				
			||||||
 | 
					if you want it, that you can change the software or use pieces of it
 | 
				
			||||||
 | 
					in new free programs; and that you know you can do these things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To protect your rights, we need to make restrictions that forbid
 | 
				
			||||||
 | 
					anyone to deny you these rights or to ask you to surrender the rights.
 | 
				
			||||||
 | 
					These restrictions translate to certain responsibilities for you if you
 | 
				
			||||||
 | 
					distribute copies of the software, or if you modify it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  For example, if you distribute copies of such a program, whether
 | 
				
			||||||
 | 
					gratis or for a fee, you must give the recipients all the rights that
 | 
				
			||||||
 | 
					you have.  You must make sure that they, too, receive or can get the
 | 
				
			||||||
 | 
					source code.  And you must show them these terms so they know their
 | 
				
			||||||
 | 
					rights.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  We protect your rights with two steps: (1) copyright the software, and
 | 
				
			||||||
 | 
					(2) offer you this license which gives you legal permission to copy,
 | 
				
			||||||
 | 
					distribute and/or modify the software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Also, for each author's protection and ours, we want to make certain
 | 
				
			||||||
 | 
					that everyone understands that there is no warranty for this free
 | 
				
			||||||
 | 
					software.  If the software is modified by someone else and passed on, we
 | 
				
			||||||
 | 
					want its recipients to know that what they have is not the original, so
 | 
				
			||||||
 | 
					that any problems introduced by others will not reflect on the original
 | 
				
			||||||
 | 
					authors' reputations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Finally, any free program is threatened constantly by software
 | 
				
			||||||
 | 
					patents.  We wish to avoid the danger that redistributors of a free
 | 
				
			||||||
 | 
					program will individually obtain patent licenses, in effect making the
 | 
				
			||||||
 | 
					program proprietary.  To prevent this, we have made it clear that any
 | 
				
			||||||
 | 
					patent must be licensed for everyone's free use or not licensed at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The precise terms and conditions for copying, distribution and
 | 
				
			||||||
 | 
					modification follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							    GNU GENERAL PUBLIC LICENSE
 | 
				
			||||||
 | 
					   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  0. This License applies to any program or other work which contains
 | 
				
			||||||
 | 
					a notice placed by the copyright holder saying it may be distributed
 | 
				
			||||||
 | 
					under the terms of this General Public License.  The "Program", below,
 | 
				
			||||||
 | 
					refers to any such program or work, and a "work based on the Program"
 | 
				
			||||||
 | 
					means either the Program or any derivative work under copyright law:
 | 
				
			||||||
 | 
					that is to say, a work containing the Program or a portion of it,
 | 
				
			||||||
 | 
					either verbatim or with modifications and/or translated into another
 | 
				
			||||||
 | 
					language.  (Hereinafter, translation is included without limitation in
 | 
				
			||||||
 | 
					the term "modification".)  Each licensee is addressed as "you".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Activities other than copying, distribution and modification are not
 | 
				
			||||||
 | 
					covered by this License; they are outside its scope.  The act of
 | 
				
			||||||
 | 
					running the Program is not restricted, and the output from the Program
 | 
				
			||||||
 | 
					is covered only if its contents constitute a work based on the
 | 
				
			||||||
 | 
					Program (independent of having been made by running the Program).
 | 
				
			||||||
 | 
					Whether that is true depends on what the Program does.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1. You may copy and distribute verbatim copies of the Program's
 | 
				
			||||||
 | 
					source code as you receive it, in any medium, provided that you
 | 
				
			||||||
 | 
					conspicuously and appropriately publish on each copy an appropriate
 | 
				
			||||||
 | 
					copyright notice and disclaimer of warranty; keep intact all the
 | 
				
			||||||
 | 
					notices that refer to this License and to the absence of any warranty;
 | 
				
			||||||
 | 
					and give any other recipients of the Program a copy of this License
 | 
				
			||||||
 | 
					along with the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You may charge a fee for the physical act of transferring a copy, and
 | 
				
			||||||
 | 
					you may at your option offer warranty protection in exchange for a fee.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  2. You may modify your copy or copies of the Program or any portion
 | 
				
			||||||
 | 
					of it, thus forming a work based on the Program, and copy and
 | 
				
			||||||
 | 
					distribute such modifications or work under the terms of Section 1
 | 
				
			||||||
 | 
					above, provided that you also meet all of these conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) You must cause the modified files to carry prominent notices
 | 
				
			||||||
 | 
					    stating that you changed the files and the date of any change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) You must cause any work that you distribute or publish, that in
 | 
				
			||||||
 | 
					    whole or in part contains or is derived from the Program or any
 | 
				
			||||||
 | 
					    part thereof, to be licensed as a whole at no charge to all third
 | 
				
			||||||
 | 
					    parties under the terms of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) If the modified program normally reads commands interactively
 | 
				
			||||||
 | 
					    when run, you must cause it, when started running for such
 | 
				
			||||||
 | 
					    interactive use in the most ordinary way, to print or display an
 | 
				
			||||||
 | 
					    announcement including an appropriate copyright notice and a
 | 
				
			||||||
 | 
					    notice that there is no warranty (or else, saying that you provide
 | 
				
			||||||
 | 
					    a warranty) and that users may redistribute the program under
 | 
				
			||||||
 | 
					    these conditions, and telling the user how to view a copy of this
 | 
				
			||||||
 | 
					    License.  (Exception: if the Program itself is interactive but
 | 
				
			||||||
 | 
					    does not normally print such an announcement, your work based on
 | 
				
			||||||
 | 
					    the Program is not required to print an announcement.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These requirements apply to the modified work as a whole.  If
 | 
				
			||||||
 | 
					identifiable sections of that work are not derived from the Program,
 | 
				
			||||||
 | 
					and can be reasonably considered independent and separate works in
 | 
				
			||||||
 | 
					themselves, then this License, and its terms, do not apply to those
 | 
				
			||||||
 | 
					sections when you distribute them as separate works.  But when you
 | 
				
			||||||
 | 
					distribute the same sections as part of a whole which is a work based
 | 
				
			||||||
 | 
					on the Program, the distribution of the whole must be on the terms of
 | 
				
			||||||
 | 
					this License, whose permissions for other licensees extend to the
 | 
				
			||||||
 | 
					entire whole, and thus to each and every part regardless of who wrote it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Thus, it is not the intent of this section to claim rights or contest
 | 
				
			||||||
 | 
					your rights to work written entirely by you; rather, the intent is to
 | 
				
			||||||
 | 
					exercise the right to control the distribution of derivative or
 | 
				
			||||||
 | 
					collective works based on the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, mere aggregation of another work not based on the Program
 | 
				
			||||||
 | 
					with the Program (or with a work based on the Program) on a volume of
 | 
				
			||||||
 | 
					a storage or distribution medium does not bring the other work under
 | 
				
			||||||
 | 
					the scope of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  3. You may copy and distribute the Program (or a work based on it,
 | 
				
			||||||
 | 
					under Section 2) in object code or executable form under the terms of
 | 
				
			||||||
 | 
					Sections 1 and 2 above provided that you also do one of the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a) Accompany it with the complete corresponding machine-readable
 | 
				
			||||||
 | 
					    source code, which must be distributed under the terms of Sections
 | 
				
			||||||
 | 
					    1 and 2 above on a medium customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b) Accompany it with a written offer, valid for at least three
 | 
				
			||||||
 | 
					    years, to give any third party, for a charge no more than your
 | 
				
			||||||
 | 
					    cost of physically performing source distribution, a complete
 | 
				
			||||||
 | 
					    machine-readable copy of the corresponding source code, to be
 | 
				
			||||||
 | 
					    distributed under the terms of Sections 1 and 2 above on a medium
 | 
				
			||||||
 | 
					    customarily used for software interchange; or,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c) Accompany it with the information you received as to the offer
 | 
				
			||||||
 | 
					    to distribute corresponding source code.  (This alternative is
 | 
				
			||||||
 | 
					    allowed only for noncommercial distribution and only if you
 | 
				
			||||||
 | 
					    received the program in object code or executable form with such
 | 
				
			||||||
 | 
					    an offer, in accord with Subsection b above.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code for a work means the preferred form of the work for
 | 
				
			||||||
 | 
					making modifications to it.  For an executable work, complete source
 | 
				
			||||||
 | 
					code means all the source code for all modules it contains, plus any
 | 
				
			||||||
 | 
					associated interface definition files, plus the scripts used to
 | 
				
			||||||
 | 
					control compilation and installation of the executable.  However, as a
 | 
				
			||||||
 | 
					special exception, the source code distributed need not include
 | 
				
			||||||
 | 
					anything that is normally distributed (in either source or binary
 | 
				
			||||||
 | 
					form) with the major components (compiler, kernel, and so on) of the
 | 
				
			||||||
 | 
					operating system on which the executable runs, unless that component
 | 
				
			||||||
 | 
					itself accompanies the executable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If distribution of executable or object code is made by offering
 | 
				
			||||||
 | 
					access to copy from a designated place, then offering equivalent
 | 
				
			||||||
 | 
					access to copy the source code from the same place counts as
 | 
				
			||||||
 | 
					distribution of the source code, even though third parties are not
 | 
				
			||||||
 | 
					compelled to copy the source along with the object code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  4. You may not copy, modify, sublicense, or distribute the Program
 | 
				
			||||||
 | 
					except as expressly provided under this License.  Any attempt
 | 
				
			||||||
 | 
					otherwise to copy, modify, sublicense or distribute the Program is
 | 
				
			||||||
 | 
					void, and will automatically terminate your rights under this License.
 | 
				
			||||||
 | 
					However, parties who have received copies, or rights, from you under
 | 
				
			||||||
 | 
					this License will not have their licenses terminated so long as such
 | 
				
			||||||
 | 
					parties remain in full compliance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  5. You are not required to accept this License, since you have not
 | 
				
			||||||
 | 
					signed it.  However, nothing else grants you permission to modify or
 | 
				
			||||||
 | 
					distribute the Program or its derivative works.  These actions are
 | 
				
			||||||
 | 
					prohibited by law if you do not accept this License.  Therefore, by
 | 
				
			||||||
 | 
					modifying or distributing the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), you indicate your acceptance of this License to do so, and
 | 
				
			||||||
 | 
					all its terms and conditions for copying, distributing or modifying
 | 
				
			||||||
 | 
					the Program or works based on it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  6. Each time you redistribute the Program (or any work based on the
 | 
				
			||||||
 | 
					Program), the recipient automatically receives a license from the
 | 
				
			||||||
 | 
					original licensor to copy, distribute or modify the Program subject to
 | 
				
			||||||
 | 
					these terms and conditions.  You may not impose any further
 | 
				
			||||||
 | 
					restrictions on the recipients' exercise of the rights granted herein.
 | 
				
			||||||
 | 
					You are not responsible for enforcing compliance by third parties to
 | 
				
			||||||
 | 
					this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  7. If, as a consequence of a court judgment or allegation of patent
 | 
				
			||||||
 | 
					infringement or for any other reason (not limited to patent issues),
 | 
				
			||||||
 | 
					conditions are imposed on you (whether by court order, agreement or
 | 
				
			||||||
 | 
					otherwise) that contradict the conditions of this License, they do not
 | 
				
			||||||
 | 
					excuse you from the conditions of this License.  If you cannot
 | 
				
			||||||
 | 
					distribute so as to satisfy simultaneously your obligations under this
 | 
				
			||||||
 | 
					License and any other pertinent obligations, then as a consequence you
 | 
				
			||||||
 | 
					may not distribute the Program at all.  For example, if a patent
 | 
				
			||||||
 | 
					license would not permit royalty-free redistribution of the Program by
 | 
				
			||||||
 | 
					all those who receive copies directly or indirectly through you, then
 | 
				
			||||||
 | 
					the only way you could satisfy both it and this License would be to
 | 
				
			||||||
 | 
					refrain entirely from distribution of the Program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If any portion of this section is held invalid or unenforceable under
 | 
				
			||||||
 | 
					any particular circumstance, the balance of the section is intended to
 | 
				
			||||||
 | 
					apply and the section as a whole is intended to apply in other
 | 
				
			||||||
 | 
					circumstances.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is not the purpose of this section to induce you to infringe any
 | 
				
			||||||
 | 
					patents or other property right claims or to contest validity of any
 | 
				
			||||||
 | 
					such claims; this section has the sole purpose of protecting the
 | 
				
			||||||
 | 
					integrity of the free software distribution system, which is
 | 
				
			||||||
 | 
					implemented by public license practices.  Many people have made
 | 
				
			||||||
 | 
					generous contributions to the wide range of software distributed
 | 
				
			||||||
 | 
					through that system in reliance on consistent application of that
 | 
				
			||||||
 | 
					system; it is up to the author/donor to decide if he or she is willing
 | 
				
			||||||
 | 
					to distribute software through any other system and a licensee cannot
 | 
				
			||||||
 | 
					impose that choice.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section is intended to make thoroughly clear what is believed to
 | 
				
			||||||
 | 
					be a consequence of the rest of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  8. If the distribution and/or use of the Program is restricted in
 | 
				
			||||||
 | 
					certain countries either by patents or by copyrighted interfaces, the
 | 
				
			||||||
 | 
					original copyright holder who places the Program under this License
 | 
				
			||||||
 | 
					may add an explicit geographical distribution limitation excluding
 | 
				
			||||||
 | 
					those countries, so that distribution is permitted only in or among
 | 
				
			||||||
 | 
					countries not thus excluded.  In such case, this License incorporates
 | 
				
			||||||
 | 
					the limitation as if written in the body of this License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  9. The Free Software Foundation may publish revised and/or new versions
 | 
				
			||||||
 | 
					of the General Public License from time to time.  Such new versions will
 | 
				
			||||||
 | 
					be similar in spirit to the present version, but may differ in detail to
 | 
				
			||||||
 | 
					address new problems or concerns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each version is given a distinguishing version number.  If the Program
 | 
				
			||||||
 | 
					specifies a version number of this License which applies to it and "any
 | 
				
			||||||
 | 
					later version", you have the option of following the terms and conditions
 | 
				
			||||||
 | 
					either of that version or of any later version published by the Free
 | 
				
			||||||
 | 
					Software Foundation.  If the Program does not specify a version number of
 | 
				
			||||||
 | 
					this License, you may choose any version ever published by the Free Software
 | 
				
			||||||
 | 
					Foundation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  10. If you wish to incorporate parts of the Program into other free
 | 
				
			||||||
 | 
					programs whose distribution conditions are different, write to the author
 | 
				
			||||||
 | 
					to ask for permission.  For software which is copyrighted by the Free
 | 
				
			||||||
 | 
					Software Foundation, write to the Free Software Foundation; we sometimes
 | 
				
			||||||
 | 
					make exceptions for this.  Our decision will be guided by the two goals
 | 
				
			||||||
 | 
					of preserving the free status of all derivatives of our free software and
 | 
				
			||||||
 | 
					of promoting the sharing and reuse of software generally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								    NO WARRANTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
				
			||||||
 | 
					FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
				
			||||||
 | 
					OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
				
			||||||
 | 
					PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
				
			||||||
 | 
					OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
				
			||||||
 | 
					TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
				
			||||||
 | 
					PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
				
			||||||
 | 
					REPAIR OR CORRECTION.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
				
			||||||
 | 
					WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
				
			||||||
 | 
					REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
				
			||||||
 | 
					INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
				
			||||||
 | 
					OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
				
			||||||
 | 
					TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
				
			||||||
 | 
					YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
				
			||||||
 | 
					PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
				
			||||||
 | 
					POSSIBILITY OF SUCH DAMAGES.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							     END OF TERMS AND CONDITIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    How to Apply These Terms to Your New Programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  If you develop a new program, and you want it to be of the greatest
 | 
				
			||||||
 | 
					possible use to the public, the best way to achieve this is to make it
 | 
				
			||||||
 | 
					free software which everyone can redistribute and change under these terms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  To do so, attach the following notices to the program.  It is safest
 | 
				
			||||||
 | 
					to attach them to the start of each source file to most effectively
 | 
				
			||||||
 | 
					convey the exclusion of warranty; and each file should have at least
 | 
				
			||||||
 | 
					the "copyright" line and a pointer to where the full notice is found.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <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.
 | 
				
			||||||
							
								
								
									
										60
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					# $Id: Makefile,v 1.1 2007/01/02 21:30:39 rschaten Exp $
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Creates documentation and tarball for shipping.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TODAY=`date "+%y%m%d"`
 | 
				
			||||||
 | 
					DIR=`basename \`pwd\``
 | 
				
			||||||
 | 
					PACKETNAME=$(DIR)_$(TODAY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usage:
 | 
				
			||||||
 | 
						@echo "Usage of this makefile:"
 | 
				
			||||||
 | 
						@echo "make docs       create documentation"
 | 
				
			||||||
 | 
						@echo "make tarball    packs a tarball for shipping"
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						@echo "For further information, consult the documentation in Readme.txt."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# doc generation
 | 
				
			||||||
 | 
					docs: readme pdf
 | 
				
			||||||
 | 
						@echo "documentation created"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					readme: doxygen
 | 
				
			||||||
 | 
						echo "This file is auto-generated from the content of binarydcf77clock.dox." > Readme.txt
 | 
				
			||||||
 | 
						echo "You'll have more fun if you read the HTML-content in htmldoc or the PDF." >> Readme.txt
 | 
				
			||||||
 | 
						echo >> Readme.txt
 | 
				
			||||||
 | 
						lynx -dump htmldoc/main.html >> Readme.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pdf: doxygen
 | 
				
			||||||
 | 
						make -C latexdoc
 | 
				
			||||||
 | 
						mv latexdoc/refman.pdf .
 | 
				
			||||||
 | 
						rm -rf latexdoc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					doxygen:
 | 
				
			||||||
 | 
						doxygen binarydcf77clock.doxygen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -rf htmldoc latexdoc Readme.txt refman.pdf
 | 
				
			||||||
 | 
						rm -f $(PACKETNAME).tar.gz
 | 
				
			||||||
 | 
						make -C firmware clean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fw:
 | 
				
			||||||
 | 
						make -C firmware
 | 
				
			||||||
 | 
						mv -v firmware/main.hex firmware/main_$(TODAY).hex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tarball: fw clean docs
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						@echo "I assume you updated the Changelog...? Press Enter to continue..."
 | 
				
			||||||
 | 
						@read
 | 
				
			||||||
 | 
						[ -e "firmware/main_$(TODAY).hex" ] || exit
 | 
				
			||||||
 | 
						rm --force $(PACKETNAME).tar.gz;            \
 | 
				
			||||||
 | 
						tar --directory=..                          \
 | 
				
			||||||
 | 
						    --exclude=$(DIR)/Makefile               \
 | 
				
			||||||
 | 
						    --exclude=CVS                           \
 | 
				
			||||||
 | 
						    --exclude=*.ps                          \
 | 
				
			||||||
 | 
						    --create                                \
 | 
				
			||||||
 | 
						    --gzip                                  \
 | 
				
			||||||
 | 
						    --verbose                               \
 | 
				
			||||||
 | 
						    --file ../$(PACKETNAME).tar.gz $(DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										155
									
								
								binarydcf77clock.dox
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								binarydcf77clock.dox
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \mainpage Binary DCF-77 Clock
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_intro Introduction
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In Germany, the official time is transmitted in a signal called DCF-77. You
 | 
				
			||||||
 | 
					 * can find many descriptions of the signal format on the internet.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The Binary DCF-77 Clock is a simple device to receive and decode the signal
 | 
				
			||||||
 | 
					 * and display the current date and time in binary form. The signal is received
 | 
				
			||||||
 | 
					 * in a stock DCF-77 receiver module, decoded with an ATmega8 microcontroller
 | 
				
			||||||
 | 
					 * and displayed in binary form on an array of LEDs. This array consists of for
 | 
				
			||||||
 | 
					 * lines with eight LEDs each. The ATmega8 is not able to control 32 LEDs at
 | 
				
			||||||
 | 
					 * once, so an SAA1064 module is used which is connected via I2C-bus.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The time should be displayed in several different binary formats, the format
 | 
				
			||||||
 | 
					 * can be selected with a simple button. The formats will be described later.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The distribution contains the firmware for the controller, the schematics,
 | 
				
			||||||
 | 
					 * the documentation and a copy of the GPL license.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_install Building and installing
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 need to customize the
 | 
				
			||||||
 | 
					 * makefile. Also, you might have to edit the array byte[] in main.c, which
 | 
				
			||||||
 | 
					 * describes the order of the output LEDs. The current order works for me
 | 
				
			||||||
 | 
					 * because I soldered the LEDs as compact as possible, it's slightly different
 | 
				
			||||||
 | 
					 * from the layout shown in the circuit.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Also, you may have to edit the Makefile to use your preferred downloader
 | 
				
			||||||
 | 
					 * with "make program". The current version is built for avrdude with a
 | 
				
			||||||
 | 
					 * USB connection to an avr109-compatible programmer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * No external crystal is needed, so you don't have to struggle with setting
 | 
				
			||||||
 | 
					 * any fuse-bits.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * After making your changes, you can compile and flash to the device:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \code
 | 
				
			||||||
 | 
					 * make program
 | 
				
			||||||
 | 
					 * \endcode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_usage Usage
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Connect the device to a DC power source with 9V. As long as no time has been
 | 
				
			||||||
 | 
					 * decoded, a running light is shown on the output LED array. The single DCF
 | 
				
			||||||
 | 
					 * indicator LED should start flashing to indicate that a signal is received.
 | 
				
			||||||
 | 
					 * It is set to on when the input signal is high, and switched off if the
 | 
				
			||||||
 | 
					 * signal is low. So you should see it flashing with one flash per second, each
 | 
				
			||||||
 | 
					 * flash being 100ms or 200ms long.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the signal is received correctly, after about two minutes the clock
 | 
				
			||||||
 | 
					 * should be able to tell the correct time.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsection sec_reading Reading the time
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The time and date are displayed in seven different styles. You can select
 | 
				
			||||||
 | 
					 * the style by pressing the button for a while. A pattern of lights indicate
 | 
				
			||||||
 | 
					 * which mode is selected, you can read it as a binary value.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsubsection sec_mode1 Mode 1: Time as binary
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This simply displays the hours, minutes and seconds as bytes, one after
 | 
				
			||||||
 | 
					 * each other. The fourth line of the display stays blank.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsubsection sec_mode2 Mode 2: Date as binary
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is like the previous, with the difference that it displays the day of
 | 
				
			||||||
 | 
					 * the month, the month and the year in the first three lines. The last line
 | 
				
			||||||
 | 
					 * shows the day of the week, monday being a 1, tuesday a 2 and so on.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsubsection sec_mode3 Mode 3: Time as BCD
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This shows the time as binary coded digits (BCD). The first line displays
 | 
				
			||||||
 | 
					 * the hours. The left four LEDs indicate the 10-hours, the right four LEDs
 | 
				
			||||||
 | 
					 * indicate the 1-hours.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In the same way, the second and third line display the minutes and the
 | 
				
			||||||
 | 
					 * seconds.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsubsection sec_mode4 Mode 4: Date as BCD
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is like the previous mode, but the date is displayed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsubsection sec_mode5 Mode 5: Time as BCD (vertically)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This shows the time in a BCD-form as described in mode 3, but the BCD-values
 | 
				
			||||||
 | 
					 * are put vertically next to each other. So in the first two colums you can
 | 
				
			||||||
 | 
					 * read the hours, the third column is empty, the fourth and fifth columns show
 | 
				
			||||||
 | 
					 * the minutes, the sixth is empty and the seventh and eighths indicate the
 | 
				
			||||||
 | 
					 * seconds.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					* \subsubsection sec_mode6 Mode 6: Date as BCD (vertically)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is like mode 5, but it displays the date.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsubsection sec_mode7 Mode 7: Unix timestamp
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is probably the least human readable format. It shows a 32-bit value of
 | 
				
			||||||
 | 
					 * the seconds since january 1st, 1970. :-)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \subsection sec_demo Demo mode
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If you connect the clock in a place with a poor DCF-reception, but want to
 | 
				
			||||||
 | 
					 * demonstrate the functions, you can use the demo mode. To toggle this, you
 | 
				
			||||||
 | 
					 * can touch and hold the button for about five seconds. Afterwards, you can
 | 
				
			||||||
 | 
					 * switch through the different display modes. The time displayed will stand
 | 
				
			||||||
 | 
					 * still, so this can be used to explain the display modes without a hurry.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Switching to demo mode is indicated by all LEDs flashing for a short moment.
 | 
				
			||||||
 | 
					 * Leaving demo mode shows an empty rectangle for a short moment.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_drawbacks Drawbacks
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * I didn't expect the DCF-signal to be so easily disturbed. In my case
 | 
				
			||||||
 | 
					 * sometimes there is no usable signal left when I put my notebook with WLAN
 | 
				
			||||||
 | 
					 * next to the clock. Fortunately, the time will be counted further until the
 | 
				
			||||||
 | 
					 * next 'correct minute' is received.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_files Files in the distribution
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - \e Readme.txt: Documentation, created from the htmldoc-directory.
 | 
				
			||||||
 | 
					 * - \e firmware: Source code of the controller firmware.
 | 
				
			||||||
 | 
					 * - \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.
 | 
				
			||||||
 | 
					 * - \e Changelog.txt: Logfile documenting changes in firm- and hardware.
 | 
				
			||||||
 | 
					 * - \e refman.pdf: Full documentation of the software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \section sec_thanks Thanks!
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * I'd like to thank <b>Michael Meier</b>, who developed and published a much
 | 
				
			||||||
 | 
					 * more sophisticated clock on his site. The SAA1064-stuff and the routine to
 | 
				
			||||||
 | 
					 * calculate the Unix timestamp are based on his project. You can find it under
 | 
				
			||||||
 | 
					 * http://www.mulder.franken.de/ntpdcfledclock/.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * And once again I'd like to give special credits to <b>Thomas Stegemann</b>
 | 
				
			||||||
 | 
					 * for help with the C 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>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
							
								
								
									
										1252
									
								
								binarydcf77clock.doxygen
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1252
									
								
								binarydcf77clock.doxygen
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								circuit/circuit.erc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								circuit/circuit.erc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					EAGLE Version 4.16r1 Copyright (c) 1988-2006 CadSoft
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Electrical Rule Check for /home/rschaten/microcontroller/binarydcf77clock/circuit/circuit.sch at 12/30/2006 10:30:30 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WARNING: Sheet 1/1: POWER Pin IC2 VEE connected to GND
 | 
				
			||||||
 | 
					ERROR: 8 OUTPUT Pins on net B$1
 | 
				
			||||||
 | 
					ERROR: 8 OUTPUT Pins on net B$2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					No board loaded - consistency has not been checked
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    2 errors
 | 
				
			||||||
 | 
					    1 warnings
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								circuit/circuit.sch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								circuit/circuit.sch
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								circuit/circuit.sch.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								circuit/circuit.sch.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								circuit/circuit.sch.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								circuit/circuit.sch.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 38 KiB  | 
							
								
								
									
										58
									
								
								circuit/partlist.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								circuit/partlist.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					Partlist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Exported from circuit.sch at 12/30/2006 10:40:23 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EAGLE Version 4.16r1 Copyright (c) 1988-2006 CadSoft
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Part     Value          Device          Package      Library        Sheet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					C1       100n           C-EU025-024X044 C025-024X044 rcl            1
 | 
				
			||||||
 | 
					C2       100n           C-EU025-024X044 C025-024X044 rcl            1
 | 
				
			||||||
 | 
					C3       470u           CPOL-EUE5-8.5   E5-8,5       rcl            1
 | 
				
			||||||
 | 
					C4       100n           C-EU025-024X044 C025-024X044 rcl            1
 | 
				
			||||||
 | 
					C5       2,7n           C-EU025-024X044 C025-024X044 rcl            1
 | 
				
			||||||
 | 
					C6       100n           C-EU025-024X044 C025-024X044 rcl            1
 | 
				
			||||||
 | 
					IC1      MEGA8-P        MEGA8-P         DIL28-3      avr            1
 | 
				
			||||||
 | 
					IC2      SAA1064        SAA1064         DIL24-6      micro-philips  1
 | 
				
			||||||
 | 
					IC3      MC7805CT       7805T           TO220H       linear         1
 | 
				
			||||||
 | 
					JP1      ISP            JP5Q            JP5Q         jumper         1
 | 
				
			||||||
 | 
					JP2      DCF77          JP4E            JP4          jumper         1
 | 
				
			||||||
 | 
					JP3                     JP1E            JP1          jumper         1
 | 
				
			||||||
 | 
					LED1                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED2                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED3                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED4                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED5                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED6                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED7                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED8                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED9                    LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED10                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED11                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED12                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED13                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED14                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED15                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED16                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED17                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED18                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED19                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED20                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED21                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED22                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED23                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED24                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED25                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED26                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED27                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED28                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED29                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED30                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED31                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED32                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					LED33                   LED3MM          LED3MM       led            1
 | 
				
			||||||
 | 
					Q2       BC547          BC547           TO92         transistor-npn 1
 | 
				
			||||||
 | 
					Q3       BC547          BC547           TO92         transistor-npn 1
 | 
				
			||||||
 | 
					R1       10k            R-EU_0207/10    0207/10      rcl            1
 | 
				
			||||||
 | 
					R3       1k             R-EU_0207/10    0207/10      rcl            1
 | 
				
			||||||
 | 
					S1                      31-XX           B3F-31XX     switch-omron   1
 | 
				
			||||||
							
								
								
									
										50
									
								
								firmware/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								firmware/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					# $Id: Makefile,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# microcontroller settings
 | 
				
			||||||
 | 
					F_CPU = 1000000UL
 | 
				
			||||||
 | 
					MCU = atmega8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AVRDUDE = avrdude -p $(MCU) -P /dev/parport0 -c stk200 -E noreset,vcc
 | 
				
			||||||
 | 
					AVRDUDE = avrdude -p $(MCU) -P /dev/tts/USB0 -b 115200 -c avr109
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMPILE = avr-gcc -Wall -Os -I../common -I. -mmcu=$(MCU) -DF_CPU=$(F_CPU) #-DDEBUG_LEVEL=2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJECTS = saa1064.o dcftime.o main.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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) -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 main.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
 | 
				
			||||||
							
								
								
									
										33
									
								
								firmware/boole.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								firmware/boole.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					#ifndef BOOLE_H
 | 
				
			||||||
 | 
					#define BOOLE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file boole.h
 | 
				
			||||||
 | 
					 * \brief Simple boolean variables
 | 
				
			||||||
 | 
					 * \author Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: boole.h,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum boolean_enum { False = 0, True = 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum boolean_enum boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline boolean boole(int test) {
 | 
				
			||||||
 | 
					    if (test == 0) {
 | 
				
			||||||
 | 
					        return False;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return True;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline const char *boolean_name(boolean value)  {
 | 
				
			||||||
 | 
					    if (value == False) {
 | 
				
			||||||
 | 
					        return "false";
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return "true";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* BOOLE_H */
 | 
				
			||||||
							
								
								
									
										444
									
								
								firmware/dcftime.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								firmware/dcftime.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,444 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file dcftime.c
 | 
				
			||||||
 | 
					 * \brief Decoder for DCF-77 time signals
 | 
				
			||||||
 | 
					 * \author Ronald Schaten & Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: dcftime.c,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "boole.h"
 | 
				
			||||||
 | 
					#include "dcftime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: define and use meaningful states for certain situations (valid time, no values received, etc.)
 | 
				
			||||||
 | 
					// TODO: find correct start of the seconds. ATM the clock is running late by one second
 | 
				
			||||||
 | 
					// TODO: check if it is possible to give DCF_RATE as parameter for init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef unsigned int dcf_sample; /**< number of the current sample */
 | 
				
			||||||
 | 
					typedef unsigned int dcf_sizetype; /**< used for the size of a month */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const dcf_sample dcf_second_samples = (DCF_RATE); /**< number of samples per second */
 | 
				
			||||||
 | 
					/** dcf signal between 30ms and 130ms => dcf logic false (lower value) */
 | 
				
			||||||
 | 
					const dcf_sample dcf_logic_false_min = (DCF_RATE)*3/100;
 | 
				
			||||||
 | 
					/** dcf signal between 30ms and 130ms => dcf logic false (upper value) */
 | 
				
			||||||
 | 
					const dcf_sample dcf_logic_false_max = (DCF_RATE)*13/100;
 | 
				
			||||||
 | 
					/** dcf signal between 140ms and 230ms => dcf logic true (lower value) */
 | 
				
			||||||
 | 
					const dcf_sample dcf_logic_true_min = (DCF_RATE)*14/100;
 | 
				
			||||||
 | 
					/** dcf signal between 140ms and 230ms => dcf logic true (upper value) */
 | 
				
			||||||
 | 
					const dcf_sample dcf_logic_true_max = (DCF_RATE)*23/100;
 | 
				
			||||||
 | 
					/** duration between begin of dcf second (== begin of signal), should be 1 * second +/- 3% (lower value) */
 | 
				
			||||||
 | 
					const dcf_sample dcf_second_tolerance_min = (DCF_RATE) - (DCF_RATE)*3/100;
 | 
				
			||||||
 | 
					/** duration between begin of dcf second (== begin of signal), should be 1 * second +/- 3% (upper value) */
 | 
				
			||||||
 | 
					const dcf_sample dcf_second_tolerance_max = (DCF_RATE) + (DCF_RATE)*3/100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** definition of logical signal states */
 | 
				
			||||||
 | 
					enum dcf_logic_signal_enum {
 | 
				
			||||||
 | 
					    dcf_signal_no, /**< no signal */
 | 
				
			||||||
 | 
					    dcf_signal_false, /**< 'false' signal */
 | 
				
			||||||
 | 
					    dcf_signal_true, /**< 'true' signal */
 | 
				
			||||||
 | 
					    dcf_signal_invalid /**< invalid signal */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of logical signal states */
 | 
				
			||||||
 | 
					typedef enum dcf_logic_signal_enum dcf_logic_signal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** format of the received data, filled during reception */
 | 
				
			||||||
 | 
					struct dcf_receiving_data_struct {
 | 
				
			||||||
 | 
					    dcf_date date; /**< date */
 | 
				
			||||||
 | 
					    dcf_time time; /**< time */
 | 
				
			||||||
 | 
					    boolean parity; /**< parity of the received data */
 | 
				
			||||||
 | 
					    boolean is_valid; /**< data is valid */
 | 
				
			||||||
 | 
					    dcf_logic_signal current_signal; /**< logical state of the received data */
 | 
				
			||||||
 | 
					    dcf_sample low_samples; /**< counts low signal samples per second */
 | 
				
			||||||
 | 
					    dcf_sample high_samples; /**< counts high signal samples per second */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of the received data, filled during reception */
 | 
				
			||||||
 | 
					typedef struct dcf_receiving_data_struct dcf_receiving_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** format of the DCF data.
 | 
				
			||||||
 | 
					 * dcf_current_datetime() and dcf_sample() may be called from different contexts. To avoid changing the current_datetime while it is read:
 | 
				
			||||||
 | 
					 * if use_first_current_datetime is true: dcf_current_datetime reads current_datetime[0] and dcf_sample changes current_datetime[1]
 | 
				
			||||||
 | 
					 * if use_first_current_datetime is false: vice versa
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct dcf_data_struct {
 | 
				
			||||||
 | 
					  dcf_datetime current_datetime[2]; /**< two full datasets */
 | 
				
			||||||
 | 
					  boolean use_first_current_datetime; /**< flag if the first or the second dataset is used */
 | 
				
			||||||
 | 
					  dcf_sample current_datetime_sample; /**< number of the current sample */
 | 
				
			||||||
 | 
					  dcf_receiving_data receiving_data; /**< data being filled */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  global data
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dcf_data_struct dcf_data; /**< full set of received dcf data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  dcf_time
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a dcf_time value.
 | 
				
			||||||
 | 
					 * \param pTime: pointer to a dcf_time variable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_time_init(dcf_time * pTime) {
 | 
				
			||||||
 | 
					    pTime->second = 0;
 | 
				
			||||||
 | 
					    pTime->minute = 0;
 | 
				
			||||||
 | 
					    pTime->hour = 0;
 | 
				
			||||||
 | 
					    pTime->is_dst = False;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Increment a time-value by one second.
 | 
				
			||||||
 | 
					 * \param pTime: pointer to a dcf_time variable
 | 
				
			||||||
 | 
					 * \return True if the date has to be incremented, too. Otherwise False.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static boolean dcf_time_inc(dcf_time * pTime) {
 | 
				
			||||||
 | 
					    ++(pTime->second);
 | 
				
			||||||
 | 
					    if (pTime->second == 60) {
 | 
				
			||||||
 | 
					        pTime->second = 0;
 | 
				
			||||||
 | 
					        ++(pTime->minute);
 | 
				
			||||||
 | 
					        if (pTime->minute == 60) {
 | 
				
			||||||
 | 
					            pTime->minute = 0;
 | 
				
			||||||
 | 
					            ++(pTime->hour);
 | 
				
			||||||
 | 
					            if (pTime->hour == 24) {
 | 
				
			||||||
 | 
					                pTime->hour = 0;
 | 
				
			||||||
 | 
					                return True;    /* overflow => increment date */
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return False;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check if a time-value makes sense.
 | 
				
			||||||
 | 
					 * \param pTime: pointer to a dcf_time variable
 | 
				
			||||||
 | 
					 * \return True if the time is logically correct. Otherwise False.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static boolean dcf_time_is_valid(dcf_time * pTime) {
 | 
				
			||||||
 | 
					    return (pTime->second <= 60)
 | 
				
			||||||
 | 
					        && (pTime->minute <= 60)
 | 
				
			||||||
 | 
					        && (pTime->hour <= 24);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  dcf_date
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a dcf_date value.
 | 
				
			||||||
 | 
					 * \param pDate: pointer to a dcf_date variable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_date_init(dcf_date * pDate) {
 | 
				
			||||||
 | 
					    pDate->dayofweek = dcf_sunday;
 | 
				
			||||||
 | 
					    pDate->dayofmonth = 1;
 | 
				
			||||||
 | 
					    pDate->month = dcf_january;
 | 
				
			||||||
 | 
					    pDate->year = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate the number of days in a month.
 | 
				
			||||||
 | 
					 * \param pDate: pointer to a dcf_time variable
 | 
				
			||||||
 | 
					 * \return The number of days in the given month.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static dcf_sizetype dcf_date_days_in_month(dcf_date * pDate) {
 | 
				
			||||||
 | 
					    switch (pDate->month) {
 | 
				
			||||||
 | 
					        case dcf_february:
 | 
				
			||||||
 | 
					            if (pDate->year % 4 != 0)
 | 
				
			||||||
 | 
					                return 28;          /* year not divisible by 4 */
 | 
				
			||||||
 | 
					            else if (pDate->year != 0)
 | 
				
			||||||
 | 
					                return 29;          /* year divisible by 4 and not divisible by 100 */
 | 
				
			||||||
 | 
					            else if (((pDate->dayofmonth % 7) + 1) != pDate->dayofweek)
 | 
				
			||||||
 | 
					                return 28;          /* year divisible by 100 and not divisible by 400 */
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                return 29;          /* year divisible by 400 */
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					              if year is divisble by 400 (eg year 2000) the 1st february is a tuesday (== 2 (== 1+1))
 | 
				
			||||||
 | 
					              if year divided by 400 remains 100 1st February is a monday
 | 
				
			||||||
 | 
					              if year divided by 400 remains 200 1st February is a saturday
 | 
				
			||||||
 | 
					              if year divided by 400 remains 300 1st February is a thursday
 | 
				
			||||||
 | 
					              this repeats every 400 years, because 400 year are 3652425/25 day
 | 
				
			||||||
 | 
					                which is 7*521775/25, therefore divisible by 7
 | 
				
			||||||
 | 
					                which means every 400 years the day of week are the same
 | 
				
			||||||
 | 
					              ! dayofmonth and dayofweek must be synchronized to get the right value
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					        case dcf_april:
 | 
				
			||||||
 | 
					        case dcf_june:
 | 
				
			||||||
 | 
					        case dcf_september:
 | 
				
			||||||
 | 
					        case dcf_november:
 | 
				
			||||||
 | 
					            return 30;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return 31;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Increment a date-value by one day.
 | 
				
			||||||
 | 
					 * \param pDate: pointer to a dcf_date variable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_date_inc(dcf_date * pDate) {
 | 
				
			||||||
 | 
					    ++(pDate->dayofweek);
 | 
				
			||||||
 | 
					    if (pDate->dayofweek == 8) {
 | 
				
			||||||
 | 
					        pDate->dayofweek = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ++(pDate->dayofmonth);
 | 
				
			||||||
 | 
					    if (pDate->dayofmonth == (dcf_date_days_in_month(pDate) + 1)) {
 | 
				
			||||||
 | 
					        pDate->dayofmonth = 1;
 | 
				
			||||||
 | 
					        ++(pDate->month);
 | 
				
			||||||
 | 
					        if (pDate->month == 13) {
 | 
				
			||||||
 | 
					            pDate->month = 1;
 | 
				
			||||||
 | 
					            ++(pDate->year);
 | 
				
			||||||
 | 
					            if (pDate->year == 100) {
 | 
				
			||||||
 | 
					                pDate->year = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check if a date-value makes sense.
 | 
				
			||||||
 | 
					 * \param pDate: pointer to a dcf_date variable
 | 
				
			||||||
 | 
					 * \return True if the date is logically correct. Otherwise False.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static boolean dcf_date_is_valid(dcf_date * pDate) {
 | 
				
			||||||
 | 
					    return (1 <= pDate->dayofweek)
 | 
				
			||||||
 | 
					        && (pDate->dayofweek <= 7)
 | 
				
			||||||
 | 
					        && (1 <= pDate->dayofmonth)
 | 
				
			||||||
 | 
					        && (pDate->dayofmonth <= dcf_date_days_in_month(pDate))
 | 
				
			||||||
 | 
					        && (1 <= pDate->month)
 | 
				
			||||||
 | 
					        && (pDate->month <= 12)
 | 
				
			||||||
 | 
					        && (pDate->year <= 99);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  dcf_datetime
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a dcf_datetime value.
 | 
				
			||||||
 | 
					 * \param pDatetime: pointer to a dcf_datetime variable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_datetime_init(dcf_datetime * pDatetime) {
 | 
				
			||||||
 | 
					    pDatetime->is_valid = False;
 | 
				
			||||||
 | 
					    pDatetime->has_signal = False;
 | 
				
			||||||
 | 
					    dcf_time_init(&(pDatetime->time));
 | 
				
			||||||
 | 
					    dcf_date_init(&(pDatetime->date));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Increment a datetime-value by one second.
 | 
				
			||||||
 | 
					 * \param pDatetime: pointer to a dcf_datetime variable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_datetime_inc(dcf_datetime * pDatetime) {
 | 
				
			||||||
 | 
					    if (dcf_time_inc(&(pDatetime->time))) {
 | 
				
			||||||
 | 
					        dcf_date_inc(&(pDatetime->date));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  dcf_receiving_data
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize a dcf_receiving_data value.
 | 
				
			||||||
 | 
					 * \param pReceive: pointer to a dcf_receiving_data variable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_receiving_data_init(dcf_receiving_data * pReceive) {
 | 
				
			||||||
 | 
					    pReceive->current_signal = dcf_signal_no;
 | 
				
			||||||
 | 
					    pReceive->parity = False;
 | 
				
			||||||
 | 
					    pReceive->is_valid = True;
 | 
				
			||||||
 | 
					    pReceive->low_samples = 0;
 | 
				
			||||||
 | 
					    pReceive->high_samples = 0;
 | 
				
			||||||
 | 
					    dcf_time_init(&(pReceive->time));
 | 
				
			||||||
 | 
					    dcf_date_init(&(pReceive->date));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Calculate the time and date while the bits are received.
 | 
				
			||||||
 | 
					 * \param signal: True if the received bit is 200ms, False if the bit is 100ms.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_logic(boolean signal) {
 | 
				
			||||||
 | 
					    dcf_data.receiving_data.parity ^= signal;
 | 
				
			||||||
 | 
					    switch (dcf_data.receiving_data.time.second) {
 | 
				
			||||||
 | 
					        case 16: dcf_data.receiving_data.parity = True;                                       break;
 | 
				
			||||||
 | 
					        case 17: dcf_data.receiving_data.time.is_dst = signal;                                break;
 | 
				
			||||||
 | 
					        case 18: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break;
 | 
				
			||||||
 | 
					        case 19: dcf_data.receiving_data.parity = True;                                       break;
 | 
				
			||||||
 | 
					        case 20: if(!signal)                        dcf_data.receiving_data.is_valid = False; break;
 | 
				
			||||||
 | 
					        case 21: dcf_data.receiving_data.time.minute =      signal ?  1 : 0;                  break;
 | 
				
			||||||
 | 
					        case 22: dcf_data.receiving_data.time.minute +=     signal ?  2 : 0;                  break;
 | 
				
			||||||
 | 
					        case 23: dcf_data.receiving_data.time.minute +=     signal ?  4 : 0;                  break;
 | 
				
			||||||
 | 
					        case 24: dcf_data.receiving_data.time.minute +=     signal ?  8 : 0;                  break;
 | 
				
			||||||
 | 
					        case 25: dcf_data.receiving_data.time.minute +=     signal ? 10 : 0;                  break;
 | 
				
			||||||
 | 
					        case 26: dcf_data.receiving_data.time.minute +=     signal ? 20 : 0;                  break;
 | 
				
			||||||
 | 
					        case 27: dcf_data.receiving_data.time.minute +=     signal ? 40 : 0;                  break;
 | 
				
			||||||
 | 
					        case 28: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break;
 | 
				
			||||||
 | 
					        case 29: dcf_data.receiving_data.time.hour =        signal ?  1 : 0;                  break;
 | 
				
			||||||
 | 
					        case 30: dcf_data.receiving_data.time.hour +=       signal ?  2 : 0;                  break;
 | 
				
			||||||
 | 
					        case 31: dcf_data.receiving_data.time.hour +=       signal ?  4 : 0;                  break;
 | 
				
			||||||
 | 
					        case 32: dcf_data.receiving_data.time.hour +=       signal ?  8 : 0;                  break;
 | 
				
			||||||
 | 
					        case 33: dcf_data.receiving_data.time.hour +=       signal ? 10 : 0;                  break;
 | 
				
			||||||
 | 
					        case 34: dcf_data.receiving_data.time.hour +=       signal ? 20 : 0;                  break;
 | 
				
			||||||
 | 
					        case 35: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break;
 | 
				
			||||||
 | 
					        case 36: dcf_data.receiving_data.date.dayofmonth =  signal ?  1 : 0;                  break;
 | 
				
			||||||
 | 
					        case 37: dcf_data.receiving_data.date.dayofmonth += signal ?  2 : 0;                  break;
 | 
				
			||||||
 | 
					        case 38: dcf_data.receiving_data.date.dayofmonth += signal ?  4 : 0;                  break;
 | 
				
			||||||
 | 
					        case 39: dcf_data.receiving_data.date.dayofmonth += signal ?  8 : 0;                  break;
 | 
				
			||||||
 | 
					        case 40: dcf_data.receiving_data.date.dayofmonth += signal ? 10 : 0;                  break;
 | 
				
			||||||
 | 
					        case 41: dcf_data.receiving_data.date.dayofmonth += signal ? 20 : 0;                  break;
 | 
				
			||||||
 | 
					        case 42: dcf_data.receiving_data.date.dayofweek =   signal ?  1 : 0;                  break;
 | 
				
			||||||
 | 
					        case 43: dcf_data.receiving_data.date.dayofweek +=  signal ?  2 : 0;                  break;
 | 
				
			||||||
 | 
					        case 44: dcf_data.receiving_data.date.dayofweek +=  signal ?  4 : 0;                  break;
 | 
				
			||||||
 | 
					        case 45: dcf_data.receiving_data.date.month =       signal ?  1 : 0;                  break;
 | 
				
			||||||
 | 
					        case 46: dcf_data.receiving_data.date.month +=      signal ?  2 : 0;                  break;
 | 
				
			||||||
 | 
					        case 47: dcf_data.receiving_data.date.month +=      signal ?  4 : 0;                  break;
 | 
				
			||||||
 | 
					        case 48: dcf_data.receiving_data.date.month +=      signal ?  8 : 0;                  break;
 | 
				
			||||||
 | 
					        case 49: dcf_data.receiving_data.date.month +=      signal ? 10 : 0;                  break;
 | 
				
			||||||
 | 
					        case 50: dcf_data.receiving_data.date.year =        signal ?  1 : 0;                  break;
 | 
				
			||||||
 | 
					        case 51: dcf_data.receiving_data.date.year +=       signal ?  2 : 0;                  break;
 | 
				
			||||||
 | 
					        case 52: dcf_data.receiving_data.date.year +=       signal ?  4 : 0;                  break;
 | 
				
			||||||
 | 
					        case 53: dcf_data.receiving_data.date.year +=       signal ?  8 : 0;                  break;
 | 
				
			||||||
 | 
					        case 54: dcf_data.receiving_data.date.year +=       signal ? 10 : 0;                  break;
 | 
				
			||||||
 | 
					        case 55: dcf_data.receiving_data.date.year +=       signal ? 20 : 0;                  break;
 | 
				
			||||||
 | 
					        case 56: dcf_data.receiving_data.date.year +=       signal ? 40 : 0;                  break;
 | 
				
			||||||
 | 
					        case 57: dcf_data.receiving_data.date.year +=       signal ? 80 : 0;                  break;
 | 
				
			||||||
 | 
					        case 58: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ++(dcf_data.receiving_data.time.second);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copy the values from receiving_data to current_datetime.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_store(void) {
 | 
				
			||||||
 | 
					    if ((dcf_data.receiving_data.is_valid)
 | 
				
			||||||
 | 
					        && dcf_time_is_valid(&(dcf_data.receiving_data.time))
 | 
				
			||||||
 | 
					        && dcf_date_is_valid(&(dcf_data.receiving_data.date))) {
 | 
				
			||||||
 | 
					        dcf_data.current_datetime_sample = 0;
 | 
				
			||||||
 | 
					        if (dcf_data.use_first_current_datetime) {
 | 
				
			||||||
 | 
					            dcf_data.current_datetime[1].time = dcf_data.receiving_data.time;
 | 
				
			||||||
 | 
					            dcf_data.current_datetime[1].date = dcf_data.receiving_data.date;
 | 
				
			||||||
 | 
					            dcf_data.current_datetime[1].is_valid = True;
 | 
				
			||||||
 | 
					            dcf_data.use_first_current_datetime = False;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            dcf_data.current_datetime[0].time = dcf_data.receiving_data.time;
 | 
				
			||||||
 | 
					            dcf_data.current_datetime[0].date = dcf_data.receiving_data.date;
 | 
				
			||||||
 | 
					            dcf_data.current_datetime[0].is_valid = True;
 | 
				
			||||||
 | 
					            dcf_data.use_first_current_datetime = True;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copy valid time and increment it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void dcf_inc(void) {
 | 
				
			||||||
 | 
					    if (dcf_data.use_first_current_datetime) {
 | 
				
			||||||
 | 
					        dcf_data.current_datetime[1] = dcf_data.current_datetime[0];
 | 
				
			||||||
 | 
					        dcf_datetime_inc(&(dcf_data.current_datetime[1]));
 | 
				
			||||||
 | 
					        dcf_data.use_first_current_datetime = False;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        dcf_data.current_datetime[0] = dcf_data.current_datetime[1];
 | 
				
			||||||
 | 
					        dcf_datetime_inc(&(dcf_data.current_datetime[0]));
 | 
				
			||||||
 | 
					        dcf_data.use_first_current_datetime = True;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  exported functions, documented in header file
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dcf_init(void) {
 | 
				
			||||||
 | 
					    dcf_data.use_first_current_datetime = True;
 | 
				
			||||||
 | 
					    dcf_data.current_datetime_sample = 0;
 | 
				
			||||||
 | 
					    dcf_datetime_init(&(dcf_data.current_datetime[0]));
 | 
				
			||||||
 | 
					    dcf_datetime_init(&(dcf_data.current_datetime[1]));
 | 
				
			||||||
 | 
					    dcf_receiving_data_init(&(dcf_data.receiving_data));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dcf_signal(boolean signal) {
 | 
				
			||||||
 | 
					    if (dcf_data.receiving_data.low_samples > dcf_second_samples) {
 | 
				
			||||||
 | 
					        if (dcf_data.receiving_data.time.second == 59) {
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.time.second = 0;
 | 
				
			||||||
 | 
					            dcf_store();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.time.second = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dcf_data.receiving_data.low_samples = 0;
 | 
				
			||||||
 | 
					        dcf_data.receiving_data.is_valid = True;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* calculate receiving date time */
 | 
				
			||||||
 | 
					    if (signal) {
 | 
				
			||||||
 | 
					        dcf_data.receiving_data.low_samples = 0;
 | 
				
			||||||
 | 
					        ++(dcf_data.receiving_data.high_samples);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ++(dcf_data.receiving_data.low_samples);
 | 
				
			||||||
 | 
					        if (dcf_data.receiving_data.high_samples == 0) {
 | 
				
			||||||
 | 
					        } else if (dcf_data.receiving_data.high_samples < dcf_logic_false_min) {
 | 
				
			||||||
 | 
					            /* too short signal */
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.is_valid = False;
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.current_signal = dcf_signal_invalid;
 | 
				
			||||||
 | 
					        } else if (dcf_data.receiving_data.high_samples < dcf_logic_false_max) {
 | 
				
			||||||
 | 
					            /* short signal, logic 0 */
 | 
				
			||||||
 | 
					            dcf_logic(False);
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.current_signal = dcf_signal_false;
 | 
				
			||||||
 | 
					        } else if (dcf_data.receiving_data.high_samples < dcf_logic_true_min) {
 | 
				
			||||||
 | 
					            /* signal cannot be assigned to true or false */
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.is_valid = False;
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.current_signal = dcf_signal_invalid;
 | 
				
			||||||
 | 
					        } else if (dcf_data.receiving_data.high_samples < dcf_logic_true_max) {
 | 
				
			||||||
 | 
					            /* long signal, logic 1 */
 | 
				
			||||||
 | 
					            dcf_logic(True);
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.current_signal = dcf_signal_true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            /* too long signal */
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.is_valid = False;
 | 
				
			||||||
 | 
					            dcf_data.receiving_data.current_signal = dcf_signal_invalid;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dcf_data.receiving_data.high_samples = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* calculate current date time */
 | 
				
			||||||
 | 
					    ++(dcf_data.current_datetime_sample);
 | 
				
			||||||
 | 
					    if (dcf_data.current_datetime_sample == dcf_second_samples) {
 | 
				
			||||||
 | 
					        dcf_data.current_datetime_sample = 0;
 | 
				
			||||||
 | 
					        dcf_inc();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dcf_datetime dcf_current_datetime(void) {
 | 
				
			||||||
 | 
					    if (dcf_data.use_first_current_datetime) {
 | 
				
			||||||
 | 
					        dcf_data.current_datetime[0].has_signal = dcf_data.receiving_data.is_valid;
 | 
				
			||||||
 | 
					        return dcf_data.current_datetime[0];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        dcf_data.current_datetime[1].has_signal = dcf_data.receiving_data.is_valid;
 | 
				
			||||||
 | 
					        return dcf_data.current_datetime[1];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *dcf_dayofweek_name(dcf_dayofweek dow) {
 | 
				
			||||||
 | 
					    switch (dow) {
 | 
				
			||||||
 | 
					        case 1:
 | 
				
			||||||
 | 
					            return "Mo";
 | 
				
			||||||
 | 
					        case 2:
 | 
				
			||||||
 | 
					            return "Tu";
 | 
				
			||||||
 | 
					        case 3:
 | 
				
			||||||
 | 
					            return "We";
 | 
				
			||||||
 | 
					        case 4:
 | 
				
			||||||
 | 
					            return "Th";
 | 
				
			||||||
 | 
					        case 5:
 | 
				
			||||||
 | 
					            return "Fr";
 | 
				
			||||||
 | 
					        case 6:
 | 
				
			||||||
 | 
					            return "Sa";
 | 
				
			||||||
 | 
					        case 7:
 | 
				
			||||||
 | 
					            return "Su";
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return "??";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *dcf_is_dst_name(dcf_is_dst dst) {
 | 
				
			||||||
 | 
					    if (dst) {
 | 
				
			||||||
 | 
					        return "ST";
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return "WT";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										127
									
								
								firmware/dcftime.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								firmware/dcftime.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
				
			|||||||
 | 
					#ifndef DCFTIME_H
 | 
				
			||||||
 | 
					#define DCFTIME_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file dcftime.h
 | 
				
			||||||
 | 
					 * \brief Decoder for DCF-77 time signals
 | 
				
			||||||
 | 
					 * \author Ronald Schaten & Thomas Stegemann
 | 
				
			||||||
 | 
					 * \version $Id: dcftime.h,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "boole.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  dcf-signal samples per second
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#ifndef DCF_RATE
 | 
				
			||||||
 | 
					#define DCF_RATE 244 /**< number of samples per second. dcf_signal() should be called this often */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if (DCF_RATE < 100) || (250 < DCF_RATE)
 | 
				
			||||||
 | 
					#error DCF_RATE should be between 100 and 250
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef unsigned int dcf_second;      /**< seconds (0-59) */
 | 
				
			||||||
 | 
					typedef unsigned int dcf_minute;      /**< minutes (0-59) */
 | 
				
			||||||
 | 
					typedef unsigned int dcf_hour;        /**< hours (0-24) */
 | 
				
			||||||
 | 
					typedef unsigned int dcf_dayofmonth;  /**< day of month (1-31) */
 | 
				
			||||||
 | 
					typedef unsigned int dcf_year;        /**< year (0-99) */
 | 
				
			||||||
 | 
					typedef boolean      dcf_is_dst;      /**< daylight saving: True: MESZ, False: MEZ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** definition of weekdays */
 | 
				
			||||||
 | 
					enum dcf_dayofweek_enum {
 | 
				
			||||||
 | 
					    dcf_monday = 1, /**< monday = 1 */
 | 
				
			||||||
 | 
					    dcf_tuesday, /**< tuesday */
 | 
				
			||||||
 | 
					    dcf_wednesday, /**< wednesday */
 | 
				
			||||||
 | 
					    dcf_thursday, /**< thursday */
 | 
				
			||||||
 | 
					    dcf_friday, /**< friday */
 | 
				
			||||||
 | 
					    dcf_saturday, /**< saturday */
 | 
				
			||||||
 | 
					    dcf_sunday, /**< sunday = 7 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of weekdays */
 | 
				
			||||||
 | 
					typedef enum dcf_dayofweek_enum dcf_dayofweek;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** definition of months */
 | 
				
			||||||
 | 
					enum dcf_month_enum {
 | 
				
			||||||
 | 
					    dcf_january = 1, /**< january = 1 */
 | 
				
			||||||
 | 
					    dcf_february, /**< february */
 | 
				
			||||||
 | 
					    dcf_march, /**< march */
 | 
				
			||||||
 | 
					    dcf_april, /**< april */
 | 
				
			||||||
 | 
					    dcf_may, /**< may */
 | 
				
			||||||
 | 
					    dcf_june, /**< june */
 | 
				
			||||||
 | 
					    dcf_july, /**< july */
 | 
				
			||||||
 | 
					    dcf_august, /**< august */
 | 
				
			||||||
 | 
					    dcf_september, /**< september */
 | 
				
			||||||
 | 
					    dcf_october, /**< october */
 | 
				
			||||||
 | 
					    dcf_november, /**< november */
 | 
				
			||||||
 | 
					    dcf_december /**< december = 12 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of months */
 | 
				
			||||||
 | 
					typedef enum dcf_month_enum dcf_month;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** format of the dcf_time */
 | 
				
			||||||
 | 
					struct dcf_time_struct {
 | 
				
			||||||
 | 
					    dcf_second second; /**< seconds */
 | 
				
			||||||
 | 
					    dcf_minute minute; /**< minutes */
 | 
				
			||||||
 | 
					    dcf_hour hour; /**< hours */
 | 
				
			||||||
 | 
					    dcf_is_dst is_dst; /**< daylight saving time */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of dcf_time */
 | 
				
			||||||
 | 
					typedef struct dcf_time_struct dcf_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** format of the dcf_date */
 | 
				
			||||||
 | 
					struct dcf_date_struct {
 | 
				
			||||||
 | 
					    dcf_dayofweek dayofweek; /**< day of week */
 | 
				
			||||||
 | 
					    dcf_dayofmonth dayofmonth; /**< day of month */
 | 
				
			||||||
 | 
					    dcf_month month; /**< month */
 | 
				
			||||||
 | 
					    dcf_year year; /**< year */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of dcf_date */
 | 
				
			||||||
 | 
					typedef struct dcf_date_struct dcf_date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** format of the dcf_datetime */
 | 
				
			||||||
 | 
					struct dcf_datetime_struct {
 | 
				
			||||||
 | 
					    dcf_time time; /**< the time */
 | 
				
			||||||
 | 
					    dcf_date date; /**< the time */
 | 
				
			||||||
 | 
					    boolean is_valid; /**< if is_valid is False: no complete signal received, do not use date and times */
 | 
				
			||||||
 | 
					    boolean has_signal; /**< if has_signal is True: currently receiving signal */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					/** definition of dcf_datetime */
 | 
				
			||||||
 | 
					typedef struct dcf_datetime_struct dcf_datetime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Initialize the DCF-module. Call dcf_init before any other DCF function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dcf_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Tell the DCF-module if the signal is high or low. This function decides if
 | 
				
			||||||
 | 
					 * the received bit is a long or a short one, and if it is usable at all. It
 | 
				
			||||||
 | 
					 * should be called regularly, the number of calls per second is defined in
 | 
				
			||||||
 | 
					 * DCF_RATE.
 | 
				
			||||||
 | 
					 * \param signal: True if the input signal is high, False if it is low.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dcf_signal(boolean signal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Fetch the current date and time.
 | 
				
			||||||
 | 
					 * \return The current date and time in a dcf_datetime structure
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					dcf_datetime dcf_current_datetime(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the name of the current weekday.
 | 
				
			||||||
 | 
					 * \param dow: Day of the current week. Monday = 1, tuesday = 2...
 | 
				
			||||||
 | 
					 * \return Pointer to the name
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const char* dcf_dayofweek_name(dcf_dayofweek dow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get the name of the current daylight saving time (summertime, wintertime).
 | 
				
			||||||
 | 
					 * \param dst: daylight saving time bit from the time signal
 | 
				
			||||||
 | 
					 * \return Pointer to the name
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const char* dcf_is_dst_name(dcf_is_dst dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										354
									
								
								firmware/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								firmware/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,354 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file main.c
 | 
				
			||||||
 | 
					 * \brief Firmware for the binary DCF-77 clock
 | 
				
			||||||
 | 
					 * \author Ronald Schaten
 | 
				
			||||||
 | 
					 * \version $Id: main.c,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					#include <avr/interrupt.h>
 | 
				
			||||||
 | 
					#include <avr/pgmspace.h>
 | 
				
			||||||
 | 
					#include <util/delay.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "saa1064.h"
 | 
				
			||||||
 | 
					#include "dcftime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t byte[4] = { 2, 3, 1, 0 }; /** the order of the connected output-LED-rows */
 | 
				
			||||||
 | 
					uint8_t output[4], outputOld[4]; /** current and old content of the LEDs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** the display-modes */
 | 
				
			||||||
 | 
					enum modes {
 | 
				
			||||||
 | 
					    timeasbinary,
 | 
				
			||||||
 | 
					    dateasbinary,
 | 
				
			||||||
 | 
					    timeasbcdhorizontal,
 | 
				
			||||||
 | 
					    dateasbcdhorizontal,
 | 
				
			||||||
 | 
					    timeasbcdvertical,
 | 
				
			||||||
 | 
					    dateasbcdvertical,
 | 
				
			||||||
 | 
					    timestamp
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					enum modes mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t demomode = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * sends the current content of output[] to the LEDs if it has changed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void setLeds(void) {
 | 
				
			||||||
 | 
					    uint8_t i;
 | 
				
			||||||
 | 
					    for (i = 0; i < 4; i++) {
 | 
				
			||||||
 | 
					        if (output[i] != outputOld[i]) {
 | 
				
			||||||
 | 
					            set_led_digit(byte[i], output[i]);
 | 
				
			||||||
 | 
					            outputOld[i] = output[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} // function setLeds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Takes the current time and converts it into different output-formats.
 | 
				
			||||||
 | 
					 * \param datetime: the current time
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void setOutput(dcf_datetime datetime) {
 | 
				
			||||||
 | 
					    uint8_t bcdlow, bcdhigh; /* takes the low and high parts when converting to BCD */
 | 
				
			||||||
 | 
					    const uint32_t TS01012000 = 946681200UL; /* The UNIX-Timestamp of 1.1.2000 */
 | 
				
			||||||
 | 
					    const uint16_t monthstarts[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /* On which day does a new month start in non-leap-years */
 | 
				
			||||||
 | 
					    const uint32_t SECONDSINADAY = (60UL * 60 * 24); /* Number of seconds in a day */
 | 
				
			||||||
 | 
					    uint32_t ts; /* takes the UNIX-Timestamp */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (mode) {
 | 
				
			||||||
 | 
					        case timeasbinary:
 | 
				
			||||||
 | 
					            /* hour, minute and second are displayed in rows */
 | 
				
			||||||
 | 
					            output[0] = datetime.time.hour;
 | 
				
			||||||
 | 
					            output[1] = datetime.time.minute;
 | 
				
			||||||
 | 
					            output[2] = datetime.time.second;
 | 
				
			||||||
 | 
					            output[3] = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case dateasbinary:
 | 
				
			||||||
 | 
					            /* day of month, month, year and day of week (starting with monday
 | 
				
			||||||
 | 
					             * = 1) are displayed in rows */
 | 
				
			||||||
 | 
					            output[0] = datetime.date.dayofmonth;
 | 
				
			||||||
 | 
					            output[1] = datetime.date.month;
 | 
				
			||||||
 | 
					            output[2] = datetime.date.year;
 | 
				
			||||||
 | 
					            output[3] = datetime.date.dayofweek;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case timeasbcdhorizontal:
 | 
				
			||||||
 | 
					            /* the time is converted to BCD, the digits are displayed by two in
 | 
				
			||||||
 | 
					             * a row */
 | 
				
			||||||
 | 
					            bcdlow  = datetime.time.hour % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.time.hour / 10;
 | 
				
			||||||
 | 
					            output[0] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.time.minute % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.time.minute / 10;
 | 
				
			||||||
 | 
					            output[1] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.time.second % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.time.second / 10;
 | 
				
			||||||
 | 
					            output[2] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            output[3] = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case dateasbcdhorizontal:
 | 
				
			||||||
 | 
					            /* the date is converted to BCD, the digits are displayed by two in
 | 
				
			||||||
 | 
					             * a row */
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.dayofmonth % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.date.dayofmonth / 10;
 | 
				
			||||||
 | 
					            output[0] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.month % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.date.month / 10;
 | 
				
			||||||
 | 
					            output[1] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.year % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.date.year / 10;
 | 
				
			||||||
 | 
					            output[2] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.dayofweek;
 | 
				
			||||||
 | 
					            bcdhigh = 0;
 | 
				
			||||||
 | 
					            output[3] = (bcdhigh << 4) | bcdlow;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case timeasbcdvertical:
 | 
				
			||||||
 | 
					            /* the time is converted to BCD, the digits are displayed in
 | 
				
			||||||
 | 
					             * columns */
 | 
				
			||||||
 | 
					            output[0] = 0;
 | 
				
			||||||
 | 
					            output[1] = 0;
 | 
				
			||||||
 | 
					            output[2] = 0;
 | 
				
			||||||
 | 
					            output[3] = 0;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.time.hour % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.time.hour / 10;
 | 
				
			||||||
 | 
					            output[0] |= ((bcdhigh & 8) << 4) | ((bcdlow & 8) << 3);
 | 
				
			||||||
 | 
					            output[1] |= ((bcdhigh & 4) << 5) | ((bcdlow & 4) << 4);
 | 
				
			||||||
 | 
					            output[2] |= ((bcdhigh & 2) << 6) | ((bcdlow & 2) << 5);
 | 
				
			||||||
 | 
					            output[3] |= ((bcdhigh & 1) << 7) | ((bcdlow & 1) << 6);
 | 
				
			||||||
 | 
					            bcdlow  = datetime.time.minute % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.time.minute / 10;
 | 
				
			||||||
 | 
					            output[0] |= ((bcdhigh & 8) << 1) | ((bcdlow & 8) << 0);
 | 
				
			||||||
 | 
					            output[1] |= ((bcdhigh & 4) << 2) | ((bcdlow & 4) << 1);
 | 
				
			||||||
 | 
					            output[2] |= ((bcdhigh & 2) << 3) | ((bcdlow & 2) << 2);
 | 
				
			||||||
 | 
					            output[3] |= ((bcdhigh & 1) << 4) | ((bcdlow & 1) << 3);
 | 
				
			||||||
 | 
					            bcdlow  = datetime.time.second % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.time.second / 10;
 | 
				
			||||||
 | 
					            output[0] |= ((bcdhigh & 8) >> 2) | ((bcdlow & 8) >> 3);
 | 
				
			||||||
 | 
					            output[1] |= ((bcdhigh & 4) >> 1) | ((bcdlow & 4) >> 2);
 | 
				
			||||||
 | 
					            output[2] |= ((bcdhigh & 2) << 0) | ((bcdlow & 2) >> 1);
 | 
				
			||||||
 | 
					            output[3] |= ((bcdhigh & 1) << 1) | ((bcdlow & 1) << 0);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case dateasbcdvertical:
 | 
				
			||||||
 | 
					            /* the date is converted to BCD, the digits are displayed in
 | 
				
			||||||
 | 
					             * columns */
 | 
				
			||||||
 | 
					            output[0] = 0;
 | 
				
			||||||
 | 
					            output[1] = 0;
 | 
				
			||||||
 | 
					            output[2] = 0;
 | 
				
			||||||
 | 
					            output[3] = 0;
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.dayofmonth % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.date.dayofmonth / 10;
 | 
				
			||||||
 | 
					            output[0] |= ((bcdhigh & 8) << 4) | ((bcdlow & 8) << 3);
 | 
				
			||||||
 | 
					            output[1] |= ((bcdhigh & 4) << 5) | ((bcdlow & 4) << 4);
 | 
				
			||||||
 | 
					            output[2] |= ((bcdhigh & 2) << 6) | ((bcdlow & 2) << 5);
 | 
				
			||||||
 | 
					            output[3] |= ((bcdhigh & 1) << 7) | ((bcdlow & 1) << 6);
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.month % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.date.month / 10;
 | 
				
			||||||
 | 
					            output[0] |= ((bcdhigh & 8) << 1) | ((bcdlow & 8) << 0);
 | 
				
			||||||
 | 
					            output[1] |= ((bcdhigh & 4) << 2) | ((bcdlow & 4) << 1);
 | 
				
			||||||
 | 
					            output[2] |= ((bcdhigh & 2) << 3) | ((bcdlow & 2) << 2);
 | 
				
			||||||
 | 
					            output[3] |= ((bcdhigh & 1) << 4) | ((bcdlow & 1) << 3);
 | 
				
			||||||
 | 
					            bcdlow  = datetime.date.year % 10;
 | 
				
			||||||
 | 
					            bcdhigh = datetime.date.year / 10;
 | 
				
			||||||
 | 
					            output[0] |= ((bcdhigh & 8) >> 2) | ((bcdlow & 8) >> 3);
 | 
				
			||||||
 | 
					            output[1] |= ((bcdhigh & 4) >> 1) | ((bcdlow & 4) >> 2);
 | 
				
			||||||
 | 
					            output[2] |= ((bcdhigh & 2) << 0) | ((bcdlow & 2) >> 1);
 | 
				
			||||||
 | 
					            output[3] |= ((bcdhigh & 1) << 1) | ((bcdlow & 1) << 0);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case timestamp:
 | 
				
			||||||
 | 
					            /* compute the UNIX-Timestamp. This function is based on http://www.mulder.franken.de/ntpdcfledclock/ */
 | 
				
			||||||
 | 
					            ts = TS01012000 + SECONDSINADAY;        /* 2000 was leap year */
 | 
				
			||||||
 | 
					            ts += SECONDSINADAY * datetime.date.year * 365;
 | 
				
			||||||
 | 
					            /* Now account for the leap years. Yes, 2000 was a leap year too. */
 | 
				
			||||||
 | 
					            ts += SECONDSINADAY * ((datetime.date.year - 1) / 4);
 | 
				
			||||||
 | 
					            ts += SECONDSINADAY * monthstarts[datetime.date.month - 1];
 | 
				
			||||||
 | 
					            if (((datetime.date.year % 4) == 0) && (datetime.date.month > 2)) {
 | 
				
			||||||
 | 
					                /* We are in a leap year and past february */
 | 
				
			||||||
 | 
					                ts += SECONDSINADAY;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ts += SECONDSINADAY * (datetime.date.dayofmonth - 1);
 | 
				
			||||||
 | 
					            ts += 3600UL * datetime.time.hour;
 | 
				
			||||||
 | 
					            ts += 60 * datetime.time.minute;
 | 
				
			||||||
 | 
					            ts += datetime.time.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            output[0] = (ts >> 24);
 | 
				
			||||||
 | 
					            output[1] = (ts >> 16);
 | 
				
			||||||
 | 
					            output[2] = (ts >>  8);
 | 
				
			||||||
 | 
					            output[3] = (ts >>  0);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} // function setOutput
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sets the output to a running light. This is used when no valid time can be
 | 
				
			||||||
 | 
					 * displayed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void setWaiting(void) {
 | 
				
			||||||
 | 
					    static uint8_t position = 0;
 | 
				
			||||||
 | 
					    output[0] = 0;
 | 
				
			||||||
 | 
					    output[1] = 0;
 | 
				
			||||||
 | 
					    output[2] = 0;
 | 
				
			||||||
 | 
					    output[3] = 0;
 | 
				
			||||||
 | 
					    if (position < 8) {
 | 
				
			||||||
 | 
					        output[0] = (1 << position);
 | 
				
			||||||
 | 
					    } else if (position == 8) {
 | 
				
			||||||
 | 
					        output[1] = 128;
 | 
				
			||||||
 | 
					    } else if (position == 9) {
 | 
				
			||||||
 | 
					        output[2] = 128;
 | 
				
			||||||
 | 
					    } else if (position == 18) {
 | 
				
			||||||
 | 
					        output[2] = 1;
 | 
				
			||||||
 | 
					    } else if (position == 19) {
 | 
				
			||||||
 | 
					        output[1] = 1;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        output[3] = (128 >> (position - 10));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    position++;
 | 
				
			||||||
 | 
					    if (position > 19) {
 | 
				
			||||||
 | 
					        position = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} // function setWaiting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Timer interrupt function. This is called on every timer-interrupt (which
 | 
				
			||||||
 | 
					 * happens 488 times per second.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void timerInterrupt(void) {
 | 
				
			||||||
 | 
					    dcf_datetime datetime; /** takes the current time and date */
 | 
				
			||||||
 | 
					    static uint8_t tickcounter; /** internal tick, is incremented with every timer-loop */
 | 
				
			||||||
 | 
					    static uint8_t keycounter = 0; /** used to defeat bouncing buttons */
 | 
				
			||||||
 | 
					    static uint8_t demomodecounter = 0; /** used to switch to demo mode */
 | 
				
			||||||
 | 
					    static uint8_t modeswitched = 0; /** set when the mode has been switched, displays bars to indicate the new mode. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tickcounter++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* on every second interrupt, check the state of the DCF-signal */
 | 
				
			||||||
 | 
					    if (tickcounter % 2) {
 | 
				
			||||||
 | 
					        if ((PINC & (1 << PINC0))) {
 | 
				
			||||||
 | 
					            // signal high
 | 
				
			||||||
 | 
					            dcf_signal(True);
 | 
				
			||||||
 | 
					            PORTC |= (1 << PINC1);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // signal low
 | 
				
			||||||
 | 
					            dcf_signal(False);
 | 
				
			||||||
 | 
					            PORTC &= ~(1 << PINC1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* on every 32nd interrupt, check if the key is pressed. After 5 loops with
 | 
				
			||||||
 | 
					     * a pressed key, switch to the next display-mode. */
 | 
				
			||||||
 | 
					    if (tickcounter % 32 == 0) {
 | 
				
			||||||
 | 
					        if (!(PINC & (1 << PINC2))) {
 | 
				
			||||||
 | 
					            // key pressed
 | 
				
			||||||
 | 
					            keycounter++;
 | 
				
			||||||
 | 
					            if (keycounter > 4) {
 | 
				
			||||||
 | 
					                // after 4 cycles with pressed key, switch to the next mode
 | 
				
			||||||
 | 
					                keycounter = 0;
 | 
				
			||||||
 | 
					                mode++;
 | 
				
			||||||
 | 
					                if (mode > timestamp) {
 | 
				
			||||||
 | 
					                    mode = timeasbinary;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                modeswitched = 5;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            demomodecounter++;
 | 
				
			||||||
 | 
					            if (demomodecounter > 75) {
 | 
				
			||||||
 | 
					                // after 75 cycles with pressed key, switch to or from demo mode
 | 
				
			||||||
 | 
					                if (demomode == 0) {
 | 
				
			||||||
 | 
					                    demomode = 1;
 | 
				
			||||||
 | 
					                    mode = timeasbinary;
 | 
				
			||||||
 | 
					                    output[0] = 255;
 | 
				
			||||||
 | 
					                    output[1] = 255;
 | 
				
			||||||
 | 
					                    output[2] = 255;
 | 
				
			||||||
 | 
					                    output[3] = 255;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    demomode = 0;
 | 
				
			||||||
 | 
					                    mode = timeasbinary;
 | 
				
			||||||
 | 
					                    output[0] = 255;
 | 
				
			||||||
 | 
					                    output[1] = 129;
 | 
				
			||||||
 | 
					                    output[2] = 129;
 | 
				
			||||||
 | 
					                    output[3] = 255;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                setLeds();
 | 
				
			||||||
 | 
					                demomodecounter = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // key unpressed
 | 
				
			||||||
 | 
					            keycounter = 0;
 | 
				
			||||||
 | 
					            demomodecounter = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* on every 128th interrupt (about 4 times per second), check if anything
 | 
				
			||||||
 | 
					     * new has to be displayed. */
 | 
				
			||||||
 | 
					    if (tickcounter % 128 == 0) {
 | 
				
			||||||
 | 
					        if (demomode == 1) {
 | 
				
			||||||
 | 
					            // set the current date and time to a fixed value to demonstrate
 | 
				
			||||||
 | 
					            // how the time is displayed
 | 
				
			||||||
 | 
					            datetime.is_valid = 1;
 | 
				
			||||||
 | 
					            datetime.time.hour = 10;
 | 
				
			||||||
 | 
					            datetime.time.minute = 35;
 | 
				
			||||||
 | 
					            datetime.time.second = 10;
 | 
				
			||||||
 | 
					            datetime.date.dayofmonth = 30;
 | 
				
			||||||
 | 
					            datetime.date.month = 12;
 | 
				
			||||||
 | 
					            datetime.date.year = 6;
 | 
				
			||||||
 | 
					            datetime.date.dayofweek = 6;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            datetime = dcf_current_datetime();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (modeswitched > 0) {
 | 
				
			||||||
 | 
					            output[0] = mode + 1;
 | 
				
			||||||
 | 
					            output[1] = mode + 1;
 | 
				
			||||||
 | 
					            output[2] = mode + 1;
 | 
				
			||||||
 | 
					            output[3] = mode + 1;
 | 
				
			||||||
 | 
					            modeswitched--;
 | 
				
			||||||
 | 
					        } else if (datetime.is_valid) {
 | 
				
			||||||
 | 
					            setOutput(datetime);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            setWaiting();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* finally, set the output */
 | 
				
			||||||
 | 
					        setLeds();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} // function timerInterrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Main-function. Initializes the hardware and starts the main loop of the
 | 
				
			||||||
 | 
					 * application.
 | 
				
			||||||
 | 
					 * \return An integer. Whatever... :-)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int main(void) {
 | 
				
			||||||
 | 
					    uint8_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* set a default display-mode */
 | 
				
			||||||
 | 
					    mode = timeasbinary;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* intialize ports */
 | 
				
			||||||
 | 
					    DDRC = (1 << DDC1); // set pin 1 to output
 | 
				
			||||||
 | 
					    PORTC = (1 << PC1) | (1 << PC2); // activate pullups on pins 1 and 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* initialize SAA1064 on i2c-bus */
 | 
				
			||||||
 | 
					    led_init();
 | 
				
			||||||
 | 
					    set_led_brightness(1);
 | 
				
			||||||
 | 
					    for (i = 0; i <= 3; i++) { /* switch off all connected LEDs */
 | 
				
			||||||
 | 
					        set_led_digit(i, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* initialize DCF77 */
 | 
				
			||||||
 | 
					    dcf_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* initialize timer */
 | 
				
			||||||
 | 
					    TCCR0 = (0 << CS02) | (1 << CS01) | (0 << CS00); // set divider to 8.
 | 
				
			||||||
 | 
					         /* The interrupt is called every 8*256 CPU-cycles, at 1MHz we get 488
 | 
				
			||||||
 | 
					          * calls per second. DCF_RATE in dcftime.h has to be set according to
 | 
				
			||||||
 | 
					          * this value. */
 | 
				
			||||||
 | 
					    sei();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (1) {                 /* main event loop */
 | 
				
			||||||
 | 
					        if (TIFR & (1 << TOV0)) {
 | 
				
			||||||
 | 
					            TIFR |= 1 << TOV0;  /* clear pending flag */
 | 
				
			||||||
 | 
					            timerInterrupt();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								firmware/saa1064.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								firmware/saa1064.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file saa1064.c
 | 
				
			||||||
 | 
					 * \brief I2C-connection to the SAA1064 LED-driver
 | 
				
			||||||
 | 
					 * \author Ronald Schaten
 | 
				
			||||||
 | 
					 * \version $Id: saa1064.c,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* based on http://www.mulder.franken.de/ntpdcfledclock/ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					#include <util/delay.h>
 | 
				
			||||||
 | 
					#include "saa1064.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The Port used for the connection */
 | 
				
			||||||
 | 
					#define LEDPORT PORTC
 | 
				
			||||||
 | 
					#define LEDPIN PINC
 | 
				
			||||||
 | 
					#define LEDDDR DDRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Which pins of the port */
 | 
				
			||||||
 | 
					#define SDAPIN PC4
 | 
				
			||||||
 | 
					#define SCLPIN PC5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* the I2C addresses of the SAA 1064 LED drivers */
 | 
				
			||||||
 | 
					#define SAA_AD1 0x70 // or 0x76?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define I2C_READ  0x01
 | 
				
			||||||
 | 
					#define I2C_WRITE 0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Should be at least 27 (80 / 3) at 8 MHz */
 | 
				
			||||||
 | 
					/* This was the conservative value used for testing. However, half as much should work as well. */
 | 
				
			||||||
 | 
					#define DELAYVAL 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void led_init(void) {
 | 
				
			||||||
 | 
					    /* activate pullups */
 | 
				
			||||||
 | 
					    LEDPORT |= (1 << SCLPIN) | (1 << SDAPIN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Send START, defined as high-to-low SDA with SCL high.
 | 
				
			||||||
 | 
					 * Expects SCL and SDA to be high already!
 | 
				
			||||||
 | 
					 * Returns with SDA and SCL low. */
 | 
				
			||||||
 | 
					static void I2C_start(void) {
 | 
				
			||||||
 | 
					    /* Change to output mode. */
 | 
				
			||||||
 | 
					    LEDDDR |= (1 << SDAPIN) | (1 << SCLPIN);
 | 
				
			||||||
 | 
					    /* change SDA to low */
 | 
				
			||||||
 | 
					    LEDPORT &= ~(1 << SDAPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    /* and SCL too */
 | 
				
			||||||
 | 
					    LEDPORT &= ~(1 << SCLPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Send STOP, defined as low-to-high SDA with SCL high.
 | 
				
			||||||
 | 
					 * Expects SCL and SDA to be low already!
 | 
				
			||||||
 | 
					 * Returns with SDA and SCL high. */
 | 
				
			||||||
 | 
					static void I2C_stop(void) {
 | 
				
			||||||
 | 
					    /* Set SCL */
 | 
				
			||||||
 | 
					    LEDPORT |= (1 << SCLPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    /* Set SDA */
 | 
				
			||||||
 | 
					    LEDPORT |= (1 << SDAPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    /* Probably safer to tristate the bus */
 | 
				
			||||||
 | 
					    LEDDDR &= ~((1 << SDAPIN) | (1 << SCLPIN));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Transmits the byte in what.
 | 
				
			||||||
 | 
					 * Returns 1 if the byte was ACKed, 0 if not.
 | 
				
			||||||
 | 
					 * Expects SCL and SDA to be low already!
 | 
				
			||||||
 | 
					 * Returns with SDA and SCL low. */
 | 
				
			||||||
 | 
					static uint8_t I2C_transmit_byte(uint8_t what) {
 | 
				
			||||||
 | 
					    uint8_t i;
 | 
				
			||||||
 | 
					    for (i = 0; i < 8; i++) {
 | 
				
			||||||
 | 
					        /* First put data on the bus */
 | 
				
			||||||
 | 
					        if (what & 0x80) {
 | 
				
			||||||
 | 
					            LEDPORT |= (1 << SDAPIN);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					        /* Then set SCL high */
 | 
				
			||||||
 | 
					        LEDPORT |= (1 << SCLPIN);
 | 
				
			||||||
 | 
					        _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					        /* Take SCL back */
 | 
				
			||||||
 | 
					        LEDPORT &= ~(1 << SCLPIN);
 | 
				
			||||||
 | 
					        _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					        /* And SDA too */
 | 
				
			||||||
 | 
					        LEDPORT &= ~(1 << SDAPIN);
 | 
				
			||||||
 | 
					        _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					        what <<= 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /* OK that was the data, now we read back the ACK */
 | 
				
			||||||
 | 
					    /* We need to tristate SDA for that */
 | 
				
			||||||
 | 
					    LEDPORT |= (1 << SDAPIN);
 | 
				
			||||||
 | 
					    LEDDDR &= ~(1 << SDAPIN);
 | 
				
			||||||
 | 
					    /* Give the device some time */
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    /* Then set SCL high */
 | 
				
			||||||
 | 
					    LEDPORT |= (1 << SCLPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    i = LEDPIN & (1 << SDAPIN);    /* Read ACK */
 | 
				
			||||||
 | 
					    /* Take SCL back */
 | 
				
			||||||
 | 
					    LEDPORT &= ~(1 << SCLPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    /* No more tristate, we pull SDA again */
 | 
				
			||||||
 | 
					    LEDPORT &= ~(1 << SDAPIN);
 | 
				
			||||||
 | 
					    LEDDDR |= (1 << SDAPIN);
 | 
				
			||||||
 | 
					    _delay_loop_1(DELAYVAL);
 | 
				
			||||||
 | 
					    return (i == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void set_led_digit(uint8_t digit, uint8_t val) {
 | 
				
			||||||
 | 
					    I2C_start();
 | 
				
			||||||
 | 
					    /* Address device */
 | 
				
			||||||
 | 
					    I2C_transmit_byte(SAA_AD1 | I2C_WRITE);
 | 
				
			||||||
 | 
					    I2C_transmit_byte((digit & 3) + 1); /* Address Digit Register on device */
 | 
				
			||||||
 | 
					    I2C_transmit_byte(val);     /* Send value for Digit */
 | 
				
			||||||
 | 
					    I2C_stop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void set_led_brightness(uint8_t led_brightness) {
 | 
				
			||||||
 | 
					    I2C_start();
 | 
				
			||||||
 | 
					    I2C_transmit_byte(SAA_AD1 | I2C_WRITE);     /* Address first driver */
 | 
				
			||||||
 | 
					    I2C_transmit_byte(0);       /* Address Config Register on device */
 | 
				
			||||||
 | 
					    I2C_transmit_byte(((led_brightness & 0x07) << 4) | 0x07);   /* Send Settings */
 | 
				
			||||||
 | 
					    I2C_stop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								firmware/saa1064.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								firmware/saa1064.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#ifndef _SAA1064_H_
 | 
				
			||||||
 | 
					#define _SAA1064_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \file saa1064.h
 | 
				
			||||||
 | 
					 * \brief I2C-connection to the SAA1064 LED-driver
 | 
				
			||||||
 | 
					 * \author Ronald Schaten
 | 
				
			||||||
 | 
					 * \version $Id: saa1064.h,v 1.1 2007/01/02 21:30:40 rschaten Exp $
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * License: See documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* based on http://www.mulder.franken.de/ntpdcfledclock/ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This sets one digit on the LED module.
 | 
				
			||||||
 | 
					 * digit   is the number of the digit (0 - 7)
 | 
				
			||||||
 | 
					 * val     is a bitfield that contains the values to set. */
 | 
				
			||||||
 | 
					void set_led_digit(uint8_t digit, uint8_t val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Configures the brightness of the LED module, or rather: the current the driver allows through them.
 | 
				
			||||||
 | 
					 * The values 0 through 7 can be used, corresponding to 0 through 21 mA */
 | 
				
			||||||
 | 
					void set_led_brightness(uint8_t led_brightness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Initialize the LED module... This basically enables the pullups on the I2C Bus pins */
 | 
				
			||||||
 | 
					void led_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Reference in New Issue
	
	Block a user