diff --git a/Changelog.txt b/Changelog.txt new file mode 100644 index 0000000..6880c6a --- /dev/null +++ b/Changelog.txt @@ -0,0 +1,5 @@ +$Id: Changelog.txt,v 1.1 2007/01/02 21:30:39 rschaten Exp $ + +* Release 07010x + +- initial release diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/License.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ff936b1 --- /dev/null +++ b/Makefile @@ -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) + diff --git a/binarydcf77clock.dox b/binarydcf77clock.dox new file mode 100644 index 0000000..9e62d43 --- /dev/null +++ b/binarydcf77clock.dox @@ -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 Michael Meier, 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 Thomas Stegemann + * 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. + * + * (c) 2006 by Ronald Schaten - http://www.schatenseite.de + */ diff --git a/binarydcf77clock.doxygen b/binarydcf77clock.doxygen new file mode 100644 index 0000000..d484dc2 --- /dev/null +++ b/binarydcf77clock.doxygen @@ -0,0 +1,1252 @@ +# Doxyfile 1.4.7 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Binary DCF-77 Clock" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = htmldoc + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latexdoc + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtfdoc + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = YES + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/circuit/circuit.erc b/circuit/circuit.erc new file mode 100644 index 0000000..3eb1235 --- /dev/null +++ b/circuit/circuit.erc @@ -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 diff --git a/circuit/circuit.sch b/circuit/circuit.sch new file mode 100644 index 0000000..735f166 Binary files /dev/null and b/circuit/circuit.sch differ diff --git a/circuit/circuit.sch.pdf b/circuit/circuit.sch.pdf new file mode 100644 index 0000000..c02c905 Binary files /dev/null and b/circuit/circuit.sch.pdf differ diff --git a/circuit/circuit.sch.png b/circuit/circuit.sch.png new file mode 100644 index 0000000..0369fad Binary files /dev/null and b/circuit/circuit.sch.png differ diff --git a/circuit/partlist.txt b/circuit/partlist.txt new file mode 100644 index 0000000..1ec3ae5 --- /dev/null +++ b/circuit/partlist.txt @@ -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 diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..da795f5 --- /dev/null +++ b/firmware/Makefile @@ -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 diff --git a/firmware/boole.h b/firmware/boole.h new file mode 100644 index 0000000..20ff117 --- /dev/null +++ b/firmware/boole.h @@ -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 */ diff --git a/firmware/dcftime.c b/firmware/dcftime.c new file mode 100644 index 0000000..09c6f63 --- /dev/null +++ b/firmware/dcftime.c @@ -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"; + } +} diff --git a/firmware/dcftime.h b/firmware/dcftime.h new file mode 100644 index 0000000..64affaa --- /dev/null +++ b/firmware/dcftime.h @@ -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 diff --git a/firmware/main.c b/firmware/main.c new file mode 100644 index 0000000..6c06802 --- /dev/null +++ b/firmware/main.c @@ -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 +#include +#include +#include + +#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; +} diff --git a/firmware/saa1064.c b/firmware/saa1064.c new file mode 100644 index 0000000..a2e427a --- /dev/null +++ b/firmware/saa1064.c @@ -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 +#include +#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(); +} diff --git a/firmware/saa1064.h b/firmware/saa1064.h new file mode 100644 index 0000000..c37e06f --- /dev/null +++ b/firmware/saa1064.h @@ -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