radioclk-1.0.ds1/0002755000175000017500000000000010513306664011450 5ustar pmpmradioclk-1.0.ds1/COPYING0000644000175000017500000004311007613226155012503 0ustar pmpm 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. radioclk-1.0.ds1/ChangeLog0000644000175000017500000000543107613226155013226 0ustar pmpm2003-01-20 Jonathan Buzzard * radioclkd.c: stricter testing of received WWVB code for errors reject received times that differ by 1000 secs from system time * radioclkd.1: removed references to WWVB decoding being untested added note about lockups with PPS kit and the DCD line 2003-01-19 Jonathan Buzzard * radioclkd.c: fixed WWVB decoding so it works against a real signal set timezone to UTC in testing mode so timestamps are actually UTC changed CalculatePPSAverage to use 59 samples and fixed indexing bug made sure clockInfo struct is properly reset at all appropriate points 2002-11-16 Jonathan Buzzard * radioclkd.c: use own replacement for mktime(), so logs are in the local time 2002-10-25 Jonathan Buzzard * radioclkd.1: merged Debian patches to the manpage for DSR line 2002-10-24 Jonathan Buzzard * radioclkd.c: fixed bugs in decoding of cts and dsr signals 2002-10-17 Jonathan Buzzard * radioclkd.c: added pulse time averaging for improved performance now decodes third clock on DSR as well 2002-04-13 Jonathan Buzzard * radioclkd.c: inital dual receiver decoding version 2002-04-10 Jonathan Buzzard * radioclkd.c: fixed array indexing bug in DecodeMSF 2002-03-31 Jonathan Buzzard * radioclkd.c: fixed DCF77 and MSF decoders to deal with daylight savings 2002-03-19 Jonathan Buzzard * radioclkd.c: make sure only one copy of radioclkd is running at any one time 2002-03-16 Jonathan Buzzard * radioclkd.1: take account of the fact two clocks can be handled on the one serial port 2002-03-12 Jonathan Buzzard * radioclkd.c: really fixed DCF77 decoding this time backed out putting timestamps with LEAP_NOTINSYNC 2002-03-05 Jonathan Buzzard * radioclkd.c: put timestamp with LEAP_NOTINSYNC on error to reduce log noise 2002-03-04 Jonathan Buzzard * radioclkd.1: removed references to DCF77 code being untested * radioclkd.c: fixed decoding of the DCF77 signal so it actually works 2002-02-08 Jonathan Buzzard * radioclkd.1: removed references to selecting radio clock type added details of how to delete the shared memory segment * radioclkd.c: switched to using time_t internally to pass the time around 2002-02-04 Jonathan Buzzard * radioclkd.c: added autodetection of which time code is being received converted WWVB decoding to more compact method 2002-02-01 Jonathan Buzzard * radioclkd.c: new more compact decoding routines for DCF77 and MSF some bug fixes in PutTimeStamp 2002-01-30 Jonathan Buzzard * radioclkd.1: New file. 2002-01-29 Jonathan Buzzard * radioclkd.c: New file. radioclk-1.0.ds1/Makefile0000644000175000017500000000224507614117354013115 0ustar pmpm# Makefile -- makefile for DCF77/MSF/WWVB time signal decoding # # VERSION=1.0 CC = /usr/bin/gcc INSTALL = /usr/bin/install DESTDIR = /usr/local MANDESTDIR = /usr/local/ CFLAGS= -Wall -g INSTALL-BIN = $(INSTALL) ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_BIN += -s endif .c.o: $(CC) $(CFLAGS) -c $< all: radioclkd radioclkd: radioclkd.o $(CC) -o $@ radioclkd.o install: install-bin install-man install-bin: $(INSTALL-BIN) -m 0755 radioclkd $(DESTDIR)/sbin install-man: $(INSTALL) -m 0644 radioclkd.1 $(DESTDIR)/man/man1 clean: rm -f *.o *.bak core radioclkd dist: clean (rm -f ChangeLog; \ rcs2log -R > ChangeLog; \ rm -rf /tmp/radioclk-$(VERSION); \ mkdir /tmp/radioclk-$(VERSION); \ cp * /tmp/radioclk-$(VERSION); \ cp -a ./debian/ /tmp/radioclk-$(VERSION); \ cd /tmp/radioclk-$(VERSION); \ find -type d | xargs chmod 755; \ find -type f | xargs chmod 644; \ find -type d | xargs chown root:root; \ find -type f | xargs chown root:root; \ cd ..; \ tar cvf radioclk-$(VERSION).tar radioclk-$(VERSION); \ gzip -9f radioclk-$(VERSION).tar; \ echo Done.) radioclk-1.0.ds1/README0000644000175000017500000000355707613226410012335 0ustar pmpmThis is a simple daemon for a computer running Linux to decode the DCF77, MSF or WWVB time signal from a receiver which pulls the DCD, CTS or DSR pin of the serial port high and low in correspondence with the radio signal. Installation should be a dodle type 'make' to build the program. Provided you have the necessary permissions on the serial port you can then test it out. You can install the program with 'make install'. By default the program and manual page are installed in /usr/local. This can be changed by editing the make file. For more details on the command line arguments to the program please consult the manual page, and check the web page http://www.buzzard.org.uk/jonathan/radioclock.html If you have problems getting the software to work using interrupts the following, command is known to resolve the problem in many instances. stty crtscts < /dev/ttyS0 where ttyS0 is the serial port the receiver is connected to. You may also want to try running watch -n 1 cat /proc/interrupts. If the number of interrupts on the serial port is not steadily increasing then there is a problem with the serial port detecting interrupts. As a last resort you may specify a -p command line option to either program, in which case the programs will poll the serial port every 5ms. This uses slightly more CPU time If you are have to compile ntp yourself to include the SHM reference clock driver then you probably want to replace refclock_shm.c in the ntp distribution with the once included here. On the replacement version you can set flag3 to 1 and the reference clock will no longer log the fact that a new time stamp has not been found in the shared memory segment. JAB. ----------------------------------------------------------------------- Jonathan A. Buzzard Email: jonathan@buzzard.org.uk Northumberland, United Kingdom. Tel: +44 1661-832195 radioclk-1.0.ds1/radioclkd.10000644000175000017500000001671510513306377013477 0ustar pmpm.\" radioclkd.1 -- manual page for radioclkd .\" .\" Copyright (c) 2002-03 Jonathan A. Buzzard (jonathan@buzzard.org.uk) .\" .\" $Log: radioclkd.1,v $ .\" Revision 1.6 2003/01/20 16:41:40 jab .\" removed references to WWVB decoding being untested .\" added note about lockups with PPS kit and the DCD line .\" .\" Revision 1.5 2002/10/25 14:15:24 jab .\" merged Debian patches to the manpage for DSR line .\" .\" Revision 1.4 2002/03/16 00:30:47 jab .\" take account of the fact two clocks can be handled on the one serial port .\" .\" Revision 1.3 2002/03/04 12:59:09 jab .\" removed references to DCF77 code being untested .\" .\" Revision 1.2 2002/02/08 15:25:37 jab .\" removed references to selecting radio clock type .\" added details of how to delete the shared memory segment .\" .\" Revision 1.1 2002/01/30 10:28:42 jab .\" Initial revision .\" .\" Permission is granted to make and distribute verbatim copies of this .\" manual provided the copyright notice and this permission notice are .\" preserved on all copies. .\" .\" Permission is granted to copy and distribute modified versions of this .\" manual under the conditions for verbatim copying, provided that the .\" entire resulting derived work is distributed under the terms of a .\" permission notice identical to this one .\" .\" The author(s) assume no responsibility for errors or omissions, or for .\" damages resulting from the use of the information contained herein. The .\" author(s) may not have taken the same level of care in the production of .\" this manual, which is licensed free of charge, as they might when working .\" professionally. .\" .\" Formatted or processed versions of this manual, if unaccompanied by .\" the source, must acknowledge the copyright and authors of this work. .\" .\" $Id: radioclkd.1,v 1.6 2003/01/20 16:41:40 jab Exp jab $ .\" .TH RADIOCLKD 1 "19 Jan 2003" "Version 1.0" "Network Time Protocol Daemon" .SH NAME radioclkd \- decode time from radio clock(s) attached to serial port .SH SYNOPSIS .B radioclkd [ \-tphv ] device .SH DESCRIPTION .B radioclkd is a simple daemon that decodes the time from a radio clock device attached to the DCD and/or CTS and/or DSR status lines of serial port of a computer. It is able to decode the DCF77, MSF and WWVB time signals. The received time is then sent to .B ntpd using the shared memory reference clock driver. The type of time signal being received is automatically determined. If you have problems getting the program to work using interrupts, the following command is known to help in many instances. If this fails you can always fall back to the polling method. .IP stty crtscts < /dev/ttyS0 .PP Details on a cheap and easy to make device for receiving these time signals can be found at .IP http://www.buzzard.org.uk/jonathan/radioclock.html .SH OPTIONS .TP .B \-p, \-\-poll Poll the serial port for changes of status in the DCD, CTS and DSR lines rather than use interrupts .TP .B \-t, \-\-test Enter test mode printing the length of each pulse and the decoded time at the end of each minute on stdout. The time is not sent to .B ntpd using the shared memory reference clock driver in this mode. .TP .B \-h, \-\-help Print a short synopsis of the command line arguments. .TP .B \-v, \-\-version Print the version number and then exit. .SH CONFIGURATION Configuration is very simple. Use server 127.127.28.0 in your ntp.conf file for a clock attached to the DCD line, server 127.127.28.1 for a clock attached to the CTS line, and server 127.127.28.2 for a clock attached to the DSR line. You will also want to use a fudge line on the server to change the displayed refid. .SH CALIBRATION Due to delays in the propogation of the radio signal, it's processing by the receiver board and the latency of the operating system the time decoded by the receiver will be slightly offset from actual UTC. Typically this delay will be less than 20ms, so unless you are very fussy about the time, or are using more than one time source, such as a GPS unit, other radio clock or NTP server on the internet you can ignore this section. The basics of the calibration procedure is to determine the average offset of the radio receiver, and use the time1 fudge factor in ntp.conf to bring the receiver as close as possible to the real time. The easiest way of determining the offset of the radio receivers time is to run it against a reference clock that does not suffer from these problems. The best reference clock would be a GPS unit. This might be a GPS unit that you don't wish to dedicate to time keeping, or a borrowed unit. If this is not possible you could use a stratum 1 server on the internet. The method of calibration is quite simple. We attach the calibration reference clock to the computer and fudge the stratum of our radio receiver up to say 5. This way we can be sure that ntpd will lock onto the calibration reference clock. We need to make sure that ntpd is configured to collect peer statistics so make sure we have some lines similar to these in ntp.conf statsdir /var/log/ntpstats/ statistics loopstats peerstats clockstats filegen peerstats file peerstats type day enable After that we restart ntpd and leave it running for several hours. We can then make a copy the peerstats file. The trick is to remove all the entries before ntpd has come into close aggrement with the calibration reference clock and then run the peer.awk script in the scripts/stats directory of the ntp distribution. This will give us a mean offset of our radio receivers in milliseconds. This can them be converted into seconds and added to the fudge line in ntp.conf for our receiver. The final step is to remove the change in stratum level for our reference clock and restart ntpd. If you move the receiver any significant distance then you will need to repeat this calibration step. Across the room or around the current building will be fine, but if you move it to the next town/city then you will need to recalibrate. .SH IN USE The version of .B ntpd that comes with most Linux distributions does not have the shared memory reference clock driver compiled in by default. This can be identified by checking the logs after .B ntpd is started. If the shared memory reference clock driver is not compiled in then the logs will contain warnings about the reference clock driver not being recognized. To compile .B ntpd with the shared memory reference clock driver you must specify the .B --enable-SHM option when running configure. Neither .B radioclkd or .B ntpd ever mark the shared memory segment for deletion. If you stop using the shared memory reference clock driver therefore any shared memory segments will persist until you reboot or manually delete the segment using .B ipcrm. The segments can be identified as the one with key 0x4e545030, 0x4e545031 or 0x4e545032 using the .B ipcs command. .SH BUGS If you are running a kernel with the PPS kit and have a clock attached to the DCD line you may experience lockups. If you encounter this problem the currently recomended solution is to move the clock to either the CTS or DSR lines. .\" The code for decoding the JJY time signal is untested against a live received .\" signal at this point in time. Though it is believed to function correctly. .\" However you should procede with caution if you intend to use the JJY time .\" signal until correct operation has been verified. .SH AUTHOR This program was written by Jonathan Buzzard and may be freely distributed under the terms of the GNU General Public License. There is ABSOLUTELY NO WARRANTY for this program. radioclk-1.0.ds1/radioclkd.c0000644000175000017500000006450207613226343013557 0ustar pmpm/* radioclkd.c -- decode DCF77/MSF/WWVB time signal from a receiver attached to * the serial port, and send to ntpd via shared memory reference * clock driver. * * Copyright (c) 2001-03 Jonathan A. Buzzard (jonathan@buzzard.org.uk) * * The SHM code to interface with the NTP SHM reference clock driver is * derived from code by David J. Schwartz * * The idea to take the average time of the best pulses in the last * minute is that of Jon Atkins * * The algorithm for UTCtime was taken from the mktime routine in libntp, though * none of the original code was used, with much of the detail removed for our * somewhat limited requirements here. * * Note: The DCF77 transmitter is located at 50:01N,9:00E * The MSF transmitter is located at 52:22N,1:11W * The WWVB transmitter is located at 40:40N,105:03W * The HGB transmitter is located at 46:24N,6:15E * The TDF transmitter is located at 47:10N,2:12E * The JJY40 transmitter is located at 37:22N,140:51E * The JJY60 transmitter is located at 33:28N,130:11E * * WARNING: This software is only year 2038 compliant if time_t and associated * time functions on your operating system is 2038 compliant. Also * note that this software is not year 3000 compliant. This is all * presuming the transmitters are still operational that far in the * future. * * $Log: radioclkd.c,v $ * Revision 2.5 2003/01/20 16:48:33 jab * stricter testing of received WWVB code for errors * reject received times that differ by 1000 secs from system time * * Revision 2.4 2003/01/19 10:41:02 jab * fixed WWVB decoding so it works against a real signal * set timezone to UTC in testing mode so timestamps are actually UTC * changed CalculatePPSAverage to use 59 samples and fixed indexing bug * made sure clockInfo struct is properly reset at all appropriate points * * Revision 2.3 2002/11/16 21:03:35 jab * use own replacement for mktime(), so logs are in the local time * * Revision 2.2 2002/10/24 11:39:09 jab * fixed bugs in decoding of cts and dsr signals * * Revision 2.1 2002/10/17 22:34:28 jab * added pulse time averaging for improved performance * now decodes third clock on DSR as well * * Revision 2.0 2002/04/13 17:47:24 jab * inital dual receiver decoding version * * Revision 1.10 2002/04/10 15:36:43 jab * fixed array indexing bug in DecodeMSF * * Revision 1.9 2002/03/31 16:13:07 jab * fixed DCF77 and MSF decoders to deal with daylight savings * * Revision 1.8 2002/03/19 11:20:36 jab * make sure only one copy of radioclkd is running at any one time * * Revision 1.7 2002/03/12 21:56:04 jab * really fixed DCF77 decoding this time * backed out putting timestamps with LEAP_NOTINSYNC * * Revision 1.6 2002/03/05 09:48:54 jab * put timestamp with LEAP_NOTINSYNC on error to reduce log noise * * Revision 1.5 2002/03/04 12:58:15 jab * fixed decoding of the DCF77 signal so it actually works * * Revision 1.4 2002/02/08 15:21:11 jab * switched to using time_t internally to pass the time around * * Revision 1.3 2002/02/04 16:25:19 jab * added autodetection of which time code is being received * converted WWVB decoding to more compact method * * Revision 1.2 2002/02/01 12:21:10 jab * new more compact decoding routines for DCF77 and MSF * some bug fixes in PutTimeStamp * * Revision 1.1 2002/01/29 00:51:02 jab * Initial revision * * 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, 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., * 675 Mass Ave, Cambridge, MA 02139, USA. * */ static const char rcsid[]="$Id: radioclkd.c,v 2.5 2003/01/20 16:48:33 jab Exp jab $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PID_FILE _PATH_VARRUN "radioclkd.pid" /* * NTPD shared memory reference clock driver structure */ #define SHMKEY 0x4e545030 struct shmTime { int mode; int count; time_t clockTimeStampSec; int clockTimeStampUSec; time_t receiveTimeStampSec; int receiveTimeStampUSec; int leap; int precision; int nsamples; int valid; int dummy[10]; }; /* * Holds all the state information about a clock receiver */ struct clockInfo { int count; int status; int error; int frame; int correct; unsigned char marker; struct timeval start; struct timeval end; int unit; time_t last; struct shmTime *stamp; char line[4]; char code[128]; struct timeval pulses[128]; }; /* * Globals, no less */ int serial; int poll; int test; jmp_buf saved; struct clockInfo dcd,cts,dsr; enum { MSF=0x01, DCF77=0x02, WWVB=0x04, JJY=0x08 }; enum { LEAP_NOWARNING=0x00, LEAP_NOTINSYNC=0x03}; /* Accuracy is assumed to be 2^PRECISION seconds -10 is approximately 980uS */ #define PRECISION (-10) #define VERSION_STRING "\ radioclkd version 1.0\n\ Copyright (c) 2001-03 Jonathan A. Buzzard \n" #define USAGE_STRING "\ Usage: radioclkd [-t] [-p] device\n\ Decode the time from a radio clock(s) attached to a serial port\n\n\ -t,--test print pulse lengths and times to stdout\n\ -p,--poll poll the serial port instead of using interrupts\n\ -h,--help display this help message\n\ -v,--version display version\n\ Report bugs to jonathan@buzzard.org.uk\n" /* * Like mktime but ignores the current time zone and daylight savings, expects * an already normalized tm stuct, and does not recompute tm_yday and tm_wday. */ time_t UTCtime(struct tm *timeptr) { int bits,direction,secs; struct tm search; time_t timep; /* calculate the number of magnitude bits in a time_t */ for (bits=0,timep=1;timep>0;bits++,timep<<=1) ; /* if time_t is signed, 0 is the median value else 1<tm_sec; timeptr->tm_sec = 0; /* binary search of the time space using the system gmtime() function */ for (;;) { search = *gmtime(&timep); /* compare the two times down to the same day */ if (((direction = (search.tm_year-timeptr->tm_year))==0) && ((direction = (search.tm_mon-timeptr->tm_mon))==0)) direction = (search.tm_mday-timeptr->tm_mday); /* compare the rest of the way if necesary */ if (direction==0) { if (((direction = (search.tm_hour-timeptr->tm_hour))==0) && ((direction = (search.tm_min-timeptr->tm_min))==0)) direction = search.tm_sec-timeptr->tm_sec; } /* is the search complete? */ if (direction==0) { timeptr->tm_sec = secs; return timep+secs; } else { if (bits--<0) return -1; if (bits<0) timep--; else if (direction>0) timep -= (time_t) 1 << bits; else timep += (time_t) 1 << bits; } } return -1; } /* * Decode the DCF77 signal. Return time since epoc on success, -1 on error. * * Note: We shift time from CET to UTC which is more useful for our purposes */ time_t DecodeDCF77(char *code, int length) { int bcd[] = { 4,3,1,4,2,1,4,2,3,4,1,4,4 }; int parity[] = { 8,7,23 }; int segment[13]; int i,j,k,sum; struct tm decoded; /* check the parity bits */ k = length-38; for(i=0;i<3;i++) { sum = 0; for(j=0;j59) || (decoded.tm_hour>23) || (decoded.tm_wday>6) || (decoded.tm_mday>31) || (decoded.tm_mon>11) ||(decoded.tm_year>199)) return -1; /* return adjusted for CET and DST */ return (UTCtime(&decoded)-((code[length-42]==1) ? 7200 : 3600)); } /* * Decode the MSF signal. Return time since epoc on success, -1 on error. */ time_t DecodeMSF(char *code, int length) { int bcd[] = { 4,4,1,4,2,4,3,2,4,3,4 }; int parity[] = { 8,11,3,13 }; int segment[11]; int i,j,k,sum; struct tm decoded; /* check the parity bits */ k = length-44; for(i=0;i<4;i++) { sum = (code[length-7+i]==2) ? 1 : 0; for(j=0;j59) || (decoded.tm_hour>23) || (decoded.tm_wday>6) || (decoded.tm_mday>31) || (decoded.tm_mon>11) ||(decoded.tm_year>199)) return -1; /* return adjusted for daylight savings */ return (UTCtime(&decoded)-((code[length-3]==2) ? 3600 : 0)); } /* * Decode the WWVB signal. Return time since epoc on success, -1 on error. */ time_t DecodeWWVB(char *code, int length) { int bcd[] = { 3,1,4,3,2,1,4,3,2,1,4,1,4,11,4,1,4 }; int months[] = { 0,31,59,90,120,151,181,212,243,273,304,334 }; int segment[17]; int i,j,k,sum; struct tm decoded; /* check framing markers exist and data pulses are of correct type */ for (i=2;i<60;i++) { j = code[length-i-1]; k = (i-1)%10; if ((k==0) && (j!=5)) return -1; else if ((k!=0) && (j!=1) && (j!=4)) return -1; } /* calculate all the individual BCD segments */ k = length-60; for(i=0;i<17;i++) { sum = 0; for(j=0;j59) || (decoded.tm_hour>23) || (decoded.tm_yday>365) || (decoded.tm_year>199)) return -1; /* set the month and day of month fields */ decoded.tm_mon = -1; for (i=11;i>=0;i--) { if (months[i]<=decoded.tm_yday) { decoded.tm_mon = i; decoded.tm_mday = 1+decoded.tm_yday-months[i]; break; } } /* adjust for leap years */ if (code[length-6]==4) { if (decoded.tm_yday>59) { decoded.tm_mday--; } else if (decoded.tm_yday==59) { decoded.tm_mon = 1; decoded.tm_mday = 29; } } if (decoded.tm_mon==-1) return -1; /* WWVB transmits the time for the minute just gone so adjust */ return (UTCtime(&decoded)+60); } /* * Print the pulse information */ void PrintPulseInfo(struct clockInfo *c) { struct timeval tv; timersub(&c->end, &c->start, &tv); fprintf(stdout, "%s: %3d %4d %9d ", c->line, c->count, c->code[c->count-1], (int) tv.tv_usec); return; } /* * Log a warning if no signal has been received in the last 5 minutes */ void LogNoSignalWarning(struct clockInfo *c, time_t now) { if (((now-c->last)>300) && (c->last>-1) && (c->error==0)) { c->error++; syslog(LOG_INFO, "no valid time received in last five minutes " "for %s line", c->line); } return; } /* * Attach the shared memory segment for the reference clock driver */ struct shmTime *AttachSharedMemory(int unit, int *shmid) { struct shmTime *shm; *shmid = shmget(SHMKEY+unit, sizeof(struct shmTime), IPC_CREAT | 0700); if (*shmid==-1) return NULL; shm = (struct shmTime *) shmat(*shmid, 0, 0); if ((shm==(void *) -1) || (shm==0)) return NULL; return shm; } /* * Set the DTR and RTS line to power the device(s) on. */ int TurnReceiverOn(int fd) { int arg; if (ioctl(fd, TIOCMGET, &arg)!=0) return -1; arg |= (TIOCM_DTR | TIOCM_RTS); if (ioctl(fd, TIOCMSET, &arg)!=0) return -1; return 0; } /* * Time out handler for the alarm on TIOCMIWAIT */ void SerialTimeoutAlarm(int sig) { // signal(SIGALRM, SerialTimeoutAlarm); // fprintf(stderr, "ALARM SIGNAL RECIEVED\n"); longjmp(saved, 1); return; } /* * Wait till either the DCD, CTS or DSR line changes status on the serial port */ int WaitOnSerialChange(int fd, struct timeval *tv) { int i,arg,cts,dcd,dsr; /* loop polling for the DCD, CTS or DSR line to change status */ if (poll==1) { if (ioctl(fd, TIOCMGET, &arg)!=0) return -1; dcd = arg & TIOCM_CD; cts = arg & TIOCM_CTS; dsr = arg & TIOCM_DSR; for (i=0;i<2000;i++) { usleep(5000); if (ioctl(fd, TIOCMGET, &arg)!=0) return -1; gettimeofday(tv, NULL); if ((dcd!=(arg & TIOCM_CD)) || (cts!=(arg & TIOCM_CTS)) || (dsr!=(arg & TIOCM_DSR))) return arg; } /* nothing changed for 10 seconds return with error */ return -1; } /* set a timeout for TIOCMIWAIT */ if (setjmp(saved)!=0) return -1; signal(SIGALRM, SerialTimeoutAlarm); alarm(10); /* wait till a serial port status change interrupt is generated */ if (ioctl(fd, TIOCMIWAIT, TIOCM_CD | TIOCM_CTS | TIOCM_DSR)!=0) return -1; gettimeofday(tv, NULL); if (ioctl(fd, TIOCMGET, &arg)!=0) return -1; /* cancel the timeout */ alarm(0); return arg; } /* * Place a time stamp in the SHM segment for the NTP reference clock driver */ void PutTimeStamp(struct timeval *local, struct timeval *radio, struct shmTime *shm, int leap) { shm->mode = 1; shm->valid = 0; __asm__ __volatile__ ("":::"memory"); shm->leap = leap; shm->precision = PRECISION; shm->clockTimeStampSec = (time_t) radio->tv_sec; shm->clockTimeStampUSec = (int) radio->tv_usec; shm->receiveTimeStampSec = (time_t) local->tv_sec; shm->receiveTimeStampUSec = (int) local->tv_usec; __asm__ __volatile__ ("":::"memory"); shm->count++; shm->valid = 1; return; } /* * Time comparison routine for the C library quicksort routine */ static int TimeCompare(const void *a, const void *b) { int timea,timeb; timea = *(int *) a; timeb = *(int *) b; if (timeatimeb) return +1; else return 0; } /* * Calculate the average measured offset of the start of the radioclock * pulses from the true time over the last minute */ int CalculatePPSAverage(struct clockInfo *c, int *average) { int i,err,count; long sum; int timediff[59] = { 0 }; /* this only works if we have a full minutes worth of clock pulses */ if (c->count<59) return -1; /* calculate the measured clock offset for the start of each pulse */ for (i=0;i<59;i++) { /* calculate time difference between computer and radio for each second marker */ err = (int) c->pulses[c->count-i-1].tv_usec; if (err>500000) err -= 1000000; /* if the time isn't close, don't bother tracking it */ if (abs(err)>128000) return -1; timediff[i] = err; } /* now sort them into order */ qsort(timediff, 59, sizeof(long), TimeCompare); /* calculate the arithmetic mean of the middle half */ count = 0; sum = 0; for (i=15;i<45;i++) { sum += timediff[i]; count++; } *average = (int) sum/count; return 0; } /* * Process a received time code and place stamp into shared memory */ void ProcessTimeCode(struct clockInfo *c, int radio) { time_t decoded,last; struct timeval computer,received; int i,shmid,average; /* decode the time */ switch (radio) { case DCF77: decoded = DecodeDCF77(c->code, c->count); break; case MSF: decoded = DecodeMSF(c->code, c->count); break; case WWVB: decoded = DecodeWWVB(c->code, c->count); break; default: c->count = 1; c->marker = 0x00; c->frame = 0; c->correct = 0; return; } /* place time stamp into shared memory segment or print on stdout */ if (test==0) { /* final sanity check on the time */ if (abs(c->start.tv_sec-decoded)>1000) { syslog(LOG_INFO, "decoded time differs from system " "time by more than 1000s ignored"); c->count = 1; c->marker = 0x00; c->frame = 0; c->correct = 0; return; } /* attach shared memory segment if not already done */ if (c->stamp==NULL) { c->stamp = AttachSharedMemory(c->unit, &shmid); if ((shmid==-1) || (c->stamp==NULL)) { syslog(LOG_INFO, "unable to attach shared " "memory for %s", c->line); return; } } /* if possible use an averaged offset */ if (CalculatePPSAverage(c, &average)<0) { computer.tv_sec = c->start.tv_sec; computer.tv_usec = c->start.tv_usec; } else { if (average<0) { computer.tv_sec = decoded-1; computer.tv_usec = average+1000000; } else { computer.tv_sec = decoded; computer.tv_usec = average; } } /* put time stamp in shared memory segment for ntpd */ received.tv_sec = decoded; received.tv_usec = 0; PutTimeStamp(&computer, &received, c->stamp, LEAP_NOWARNING); /* log any errors in getting the time */ last = decoded-c->last; if ((last>3600) && (c->error>0)) { syslog(LOG_INFO, " %ldh %ldm since previous valid time " "for %s line", last/3600, (last%3600)/60, c->line); } else if ((last>300) && (c->error>0)) { syslog(LOG_INFO, " %ldm since previous valid time for %s" " line", last/60, c->line); } } else { /* any valid time is printed in testing mode */ for (i=1;icount;i++) fprintf(stdout, "%1d", c->code[i]); fprintf(stdout, "\nUTC: %s", ctime(&decoded)); } /* reset the error warning and set last stamp time */ c->error = 0; c->last = decoded; /* setup for receiving the next minute of pulses */ c->count = 1; c->marker = 0x00; c->frame = 0; c->correct = 0; return; } /* * Process a status change on the serial port to calculate the pulse type. * If a minute marker is present send time stamp to ntpd. */ void ProcessStatusChange(struct clockInfo *c, int arg, struct timeval *tv) { struct timeval length; if ((!arg) && (c->status==1)) { c->status = 0; c->start.tv_sec = tv->tv_sec; c->start.tv_usec = tv->tv_usec; timersub(&c->start, &c->end, &length); /* check for the DCF77 minute marker */ if ((length.tv_sec==1) && (length.tv_usec>=760000) && (length.tv_usec<=950000) && (c->count>44)) { c->pulses[c->count].tv_sec = c->start.tv_sec; c->pulses[c->count].tv_usec = c->start.tv_usec; ProcessTimeCode(c, DCF77); return; } /* check to see if bit B of the MSF code set */ if ((length.tv_usec>=60000) && (length.tv_usec<=150000)) { c->code[c->count-1] = 3; c->correct = 1; } } else if ((arg) && (c->status==0)) { c->status = 1; c->end.tv_sec = tv->tv_sec; c->end.tv_usec = tv->tv_usec; timersub(&c->end, &c->start, &length); if (c->correct==1) { /* make a correction for MSF bit B being set */ c->correct = 0; return; } else if ((length.tv_usec>=60000) && (length.tv_usec<150000)) { c->code[c->count] = 0; c->pulses[c->count].tv_sec = c->start.tv_sec; c->pulses[c->count].tv_usec = c->start.tv_usec; c->count++; c->frame = 0; c->marker = c->marker<<1; } else if ((length.tv_usec>=160000) && (length.tv_usec<250000)) { c->code[c->count] = 1; c->pulses[c->count].tv_sec = c->start.tv_sec; c->pulses[c->count].tv_usec = c->start.tv_usec; c->count++; c->frame = 0; c->marker = (c->marker<<1) | 1; } else if ((length.tv_usec>=260000) && (length.tv_usec<350000)) { c->code[c->count] = 2; c->pulses[c->count].tv_sec = c->start.tv_sec; c->pulses[c->count].tv_usec = c->start.tv_usec; c->count++; c->frame = 0; c->marker = (c->marker<<1) | 1; } else if ((length.tv_usec>=460000) && (length.tv_usec<550000)) { c->code[c->count] = 4; c->pulses[c->count].tv_sec = c->start.tv_sec; c->pulses[c->count].tv_usec = c->start.tv_usec; c->count++; c->frame = 0; /* check for MSF minute marker */ if ((c->marker==0x7e) && (c->count>42)) { ProcessTimeCode(c, MSF); return; } } else if ((length.tv_usec>=760000) && (length.tv_usec<850000)) { c->code[c->count] = 5; c->pulses[c->count].tv_sec = c->start.tv_sec; c->pulses[c->count].tv_usec = c->start.tv_usec; c->count++; c->frame++; /* check for the WWVB minute marker */ if ((c->frame==2) && (c->count>60)) { ProcessTimeCode(c, WWVB); return; } } else { /* unknown pulse must be an error reset */ c->count = 1; c->marker = 0x00; c->frame = 0; c->correct = 0; } } /* check for missing minute marker and reset if needed */ if (c->count==128) { c->count = 1; c->marker = 0x00; c->frame = 0; c->correct = 0; } return; } /* * Catch any signals sent, and exit cleanly. */ void Catch(int sig) { if (test==0) { syslog(LOG_INFO, "Exiting..."); unlink(PID_FILE); munlockall(); if (dcd.stamp!=NULL) shmdt(dcd.stamp); if (cts.stamp!=NULL) shmdt(cts.stamp); if (dsr.stamp!=NULL) shmdt(dsr.stamp); } else { fprintf(stderr, "radioclkd: Exiting...\n" ); } close(serial); exit(0); } /* * Entry point. */ int main(int argc, char *argv[]) { int i,pid,arg; struct sched_param schedp; struct timeval tv; time_t now; FILE *str; char devname[16] = "/dev/"; /* process the command line arguments */ poll = 0; test = 0; for (i=1;i #endif #if defined(REFCLOCK) && defined(CLOCK_SHM) #include "ntpd.h" #undef fileno #include "ntp_io.h" #undef fileno #include "ntp_refclock.h" #undef fileno #include "ntp_unixtime.h" #undef fileno #include "ntp_stdlib.h" #undef fileno #include #undef fileno #ifndef SYS_WINNT # include # include # include # include # include #endif /* * This driver supports a reference clock attached thru shared memory */ /* * SHM interface definitions */ #define PRECISION (-1) /* precision assumed (0.5 s) */ #define REFID "SHM" /* reference ID */ #define DESCRIPTION "SHM/Shared memory interface" #define NSAMPLES 3 /* stages of median filter */ /* * Function prototypes */ static int shm_start (int, struct peer *); static void shm_shutdown (int, struct peer *); static void shm_poll (int unit, struct peer *); /* * Transfer vector */ struct refclock refclock_shm = { shm_start, /* start up driver */ shm_shutdown, /* shut down driver */ shm_poll, /* transmit poll message */ noentry, /* not used */ noentry, /* initialize driver (not used) */ noentry, /* not used */ NOFLAGS /* not used */ }; struct shmTime { int mode; /* 0 - if valid set * use values, * clear valid * 1 - if valid set * if count before and after read of values is equal, * use values * clear valid */ int count; time_t clockTimeStampSec; int clockTimeStampUSec; time_t receiveTimeStampSec; int receiveTimeStampUSec; int leap; int precision; int nsamples; int valid; int dummy[10]; }; struct shmTime *getShmTime (int unit) { #ifndef SYS_WINNT int shmid=0; assert (unit<10); /* MAXUNIT is 4, so should never happen */ shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|(unit<2?0700:0777)); if (shmid==-1) { /*error */ msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno)); return 0; } else { /* no error */ struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); if ((int)(long)p==-1) { /* error */ msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno)); return 0; } return p; } #else char buf[10]; LPSECURITY_ATTRIBUTES psec=0; HANDLE shmid=0; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; sprintf (buf,"NTP%d",unit); if (unit>=2) { /* world access */ if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit); return 0; } if (!SetSecurityDescriptorDacl(&sd,1,0,0)) { msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit); return 0; } sa.nLength=sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor=&sd; sa.bInheritHandle=0; psec=&sa; } shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, 0, sizeof (struct shmTime),buf); if (!shmid) { /*error*/ char buf[1000]; FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (), 0, buf, sizeof (buf), 0); msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf); return 0; } else { struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); if (p==0) { /*error*/ char buf[1000]; FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (), 0, buf, sizeof (buf), 0); msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf); return 0; } return p; } #endif return 0; } /* * shm_start - attach to shared memory */ static int shm_start( int unit, struct peer *peer ) { struct refclockproc *pp; pp = peer->procptr; pp->io.clock_recv = noentry; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = -1; pp->unitptr = (caddr_t)getShmTime(unit); /* * Initialize miscellaneous peer variables */ memcpy((char *)&pp->refid, REFID, 4); if (pp->unitptr!=0) { ((struct shmTime*)pp->unitptr)->precision=PRECISION; peer->precision = ((struct shmTime*)pp->unitptr)->precision; ((struct shmTime*)pp->unitptr)->valid=0; ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES; pp->clockdesc = DESCRIPTION; return (1); } else { return 0; } } /* * shm_shutdown - shut down the clock */ static void shm_shutdown( int unit, struct peer *peer ) { register struct shmTime *up; struct refclockproc *pp; pp = peer->procptr; up = (struct shmTime *)pp->unitptr; #ifndef SYS_WINNT shmdt (up); #else UnmapViewOfFile (up); #endif } /* * shm_poll - called by the transmit procedure */ static void shm_poll( int unit, struct peer *peer ) { register struct shmTime *up; struct refclockproc *pp; /* * This is the main routine. It snatches the time from the shm * board and tacks on a local timestamp. */ pp = peer->procptr; up = (struct shmTime*)pp->unitptr; if (up==0) { /* try to map again - this may succeed if meanwhile some- body has ipcrm'ed the old (unaccessible) shared mem segment */ pp->unitptr = (caddr_t)getShmTime(unit); up = (struct shmTime*)pp->unitptr; } if (up==0) { refclock_report(peer, CEVNT_FAULT); return; } if (up->valid) { struct timeval tvr; struct timeval tvt; struct tm *t; int ok=1; switch (up->mode) { case 0: { tvr.tv_sec=up->receiveTimeStampSec; tvr.tv_usec=up->receiveTimeStampUSec; tvt.tv_sec=up->clockTimeStampSec; tvt.tv_usec=up->clockTimeStampUSec; } break; case 1: { int cnt=up->count; tvr.tv_sec=up->receiveTimeStampSec; tvr.tv_usec=up->receiveTimeStampUSec; tvt.tv_sec=up->clockTimeStampSec; tvt.tv_usec=up->clockTimeStampUSec; ok=(cnt==up->count); } break; default: msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode); } up->valid=0; if (ok) { TVTOTS(&tvr,&pp->lastrec); pp->lastrec.l_ui += JAN_1970; /* pp->lasttime = current_time; */ pp->polls++; t=gmtime (&tvt.tv_sec); pp->day=t->tm_yday+1; pp->hour=t->tm_hour; pp->minute=t->tm_min; pp->second=t->tm_sec; pp->msec=0; pp->usec=tvt.tv_usec; peer->precision=up->precision; pp->leap=up->leap; } else { refclock_report(peer, CEVNT_FAULT); msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); return; } } else { refclock_report(peer, CEVNT_TIMEOUT); if (!(pp->sloppyclockflag & CLK_FLAG3)) msyslog (LOG_NOTICE, "SHM: no new value found in shared memory"); return; } if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } refclock_receive(peer); } #else int refclock_shm_bs; #endif /* REFCLOCK */