[zaptel-commits] tzafrir: branch tzafrir/xpp_1.2 r1533 -
/team/tzafrir/xpp_1.2/xpp/utils/
zaptel-commits at lists.digium.com
zaptel-commits at lists.digium.com
Tue Oct 24 13:32:08 MST 2006
Author: tzafrir
Date: Tue Oct 24 15:32:07 2006
New Revision: 1533
URL: http://svn.digium.com/view/zaptel?rev=1533&view=rev
Log:
adj_clock (missing from previous commit) : sync system clock from Zaptel clock
Added:
team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8 (with props)
team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c (with props)
Added: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8
URL: http://svn.digium.com/view/zaptel/team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8?rev=1533&view=auto
==============================================================================
--- team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8 (added)
+++ team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8 Tue Oct 24 15:32:07 2006
@@ -1,0 +1,144 @@
+." $Id$
+.TH adj_clock 8 "2006-10-18"
+.SH "NAME"
+adj_clock \(em Synchronize system clock to zaptel clock
+.SH "SYNOPSIS"
+.B adj_clock
+.I [ -c
+.B count
+.I ] [ -i
+.B interval
+.I ] [ -t
+.B period
+.I ] [ -v ]
+
+.SH "DESCRIPTION"
+.B adj_clock
+compares synchronizes the system clock from Zaptel's clock: in each cycle
+It will read 1024 *
+.B interval
+ticks from a Zaptel pseudo channel, which should take exactly
+.B interval
+seconds. It measures the time it did take, and uses
+.I adjtimex(3)
+to fix the system clock accordingly.
+
+Note that NTP servers usually use adjtimex. You may get strange behaviour
+if you have a NTP server (such as ntpd(8)) running on the system.
+
+Output is sent to both the standard error and to the syslog. Syslog
+messages are with facility daemon.
+
+.SH OPTIONS
+.I -c
+.B count
+.RS
+Run just
+.B count
+synchronization cycles. Default is to run forever.
+.RE
+
+.I -i
+.B interval
+.RS
+Loop interval (in seconds). Optional, as program should provide a sane value.
+
+Small values allow faster synchronization when the system is quiet. Even
+a value as low as 10 should work. However they are much more suspectable
+to short interruptions.
+
+.RE
+
+.I -t
+.B period
+.RS
+Set the synchronization tolerance priod (micro-seconds). The default
+is 100. Don't touch it unless you know what you're doing.
+.RE
+
+.I -v
+.RS
+Be more verbose: log status messages even when synchronized.
+.RE
+
+.SH FILES
+.B /dev/zap/pseudo
+.RS
+.RE
+The device file used to open a "pseudo" channel (a channels that
+constantly streams voice and is synchronized by the master Zaptel
+device).
+
+.SH SYNCHRONIZATION
+Some more technical details. This explains the strange numbers the
+program prints.
+
+In each cycle
+.B adj_clock
+measures
+.B interval
+seconds using Zaptel ticks. It then compares that to the system time
+from gettimeofday(2). It then calls adjtimex(2) to slightly change the
+rate of the system clock. It uses two parameters:
+.B ticks,
+which is a more
+coarse one (1 tick will give roughly a change of rate of 9 seconds per
+day) and
+.I frequency,
+which allows much finer settings.
+
+The program tries to set what it can by ticks, and the rest through
+frequency. It considers itself "synchronized" when the rate difference
+is small enough so
+.I (a)
+It does not have to use ticks anymore. And
+.I (b)
+The rest of the interval to change is smaller than the tolerance period
+(100 micro-seconds, by default).
+
+The meaning of the parameters it prints is, thus:
+
+.I interval
+.RS
+The current interval parameter (seconds).
+.RE
+
+.I diff_tick
+.RS
+The number of ticks it tries to set through adjtimex(2).
+Anything different than 0 means we're still way off mark.
+.RE
+
+.I diff_usec
+.RS
+The time difference (micro-seconds) that we need to overcome in the
+first place. This is the difference between the system clock and the
+measured zaptel clock.
+.RE
+
+.I usec_left
+.RS
+How much of this difference (microseconds) we still need to adjust
+after using ticks. This should be low enough (less than the tolerance
+period).
+.RE
+
+.SH SIGNALS
+.B adj_clock
+is so far an interactive program, and thus killed by SIGHUP. SIGUSR is
+used to increase verbosity level and SIGUSR2 is used to reset verbosity
+level to 0. When SIGUSR1 is recieved a status message will also be sent
+to the logs.
+
+.SH SEE ALSO
+ztcfg(8), zttest(8), adjtimex(2), gettimeofday(2), adjtimex(8)
+
+.SH AUTHOR
+
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
Propchange: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.8
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c
URL: http://svn.digium.com/view/zaptel/team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c?rev=1533&view=auto
==============================================================================
--- team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c (added)
+++ team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c Tue Oct 24 15:32:07 2006
@@ -1,0 +1,228 @@
+/*
+ * Written by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+ * Copyright (C) 2006, Xorcom
+ *
+ * Derived from zttest.c
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <sys/timex.h>
+#include <linux/param.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <math.h>
+
+static const char *rcsid = "$Id$";
+
+#define FREQ_PER_TICK (64*1024)
+#define USEC_PER_ZAP_TICK 1000 /* Zaptel tick in usec */
+#define USER_HZ 100
+#define SYNC_TOLERANCE 100
+#define DEFAULT_INTERVAL 60
+
+static const char *program;
+static int synced_time; /* time (seconds) we are so far synced */
+static int verbose = 0;
+static int sync_tolerance = 100;
+
+void usage() {
+ fprintf(stderr, "%s: synchronize system clock from zaptel clock.\n"
+ "Version: %s\n"
+ "\n"
+ "Usage: %s [ -c COUNT ] [-i INTERVAL] [ -t PERIOD ] [-v]\n"
+ " %s -h\n"
+ "\n"
+ "Options:\n"
+ " -c only run COUNT cycles of synchronization (default: forever).\n"
+ " -i set cycle Interval to INTERVAL (in seconds. Default: %d).\n"
+ " -t sync tolerance to PERIOD (in usec. Default: %d). For debugging.\n"
+ " -v Be more Verbose\n"
+ " -h Print this Help text and exit.\n"
+ "", program, rcsid, program, program, DEFAULT_INTERVAL,
+ sync_tolerance);
+}
+
+/* based on zttest.c */
+
+/*
+ * Print a message to the log according to the value of synced_time
+ *
+ * All parameters are for the "Not Synced" warning message.
+ * TODO: Find a better way.
+ */
+void status_message(void) {
+ if (synced_time == 0)
+ syslog(LOG_NOTICE, "Not Synced.\n");
+ else
+ syslog(LOG_INFO, "Good Sync for %d seconds\n", synced_time);
+
+ return;
+}
+
+/*
+ * interval: period, in seconds
+ * diff_usec: Current offset, in micro-seconds.
+ */
+int clock_sync(int interval, int diff_usec)
+{
+ struct timex cur_time = {.modes=0}; /* just query */
+ int diff_tick; /* Difference in adjtimex ticks */
+ int req_tick; /* Required adjtimex tick value */
+ long long diff_freq;
+ long long req_freq;
+ int usec_left; /* Usec adjusted by frequency */
+ int ret;
+
+ ret = adjtimex(&cur_time);
+
+ diff_tick = diff_usec / (interval * USER_HZ);
+ usec_left = diff_usec - diff_tick * (interval * USER_HZ);
+ diff_freq = usec_left * FREQ_PER_TICK / interval;
+
+ req_tick = cur_time.tick - diff_tick;
+ req_freq = cur_time.freq - diff_freq;
+
+ if(!diff_tick && abs(usec_left) < sync_tolerance)
+ synced_time += interval;
+ else
+ synced_time = 0;
+ status_message();
+ if (verbose || !synced_time)
+ syslog(LOG_INFO, "interval: %d, diff_tick: %d, diff_usec: %d, usec_left: %d.\n",
+ interval, diff_tick, diff_usec, usec_left);
+
+ /* set the clock rate */
+ cur_time.freq = req_freq;
+ cur_time.tick = req_tick;
+ cur_time.modes = ADJ_TICK | ADJ_FREQUENCY;
+ ret = adjtimex(&cur_time);
+ if (ret < 0)
+ syslog(LOG_ERR, "Adjtimex failed to set frequency. New frequency: %lld. Error: %d (%s)\n",
+ req_freq, errno, strerror(errno));
+ return 0;
+}
+
+static int pass = 0;
+
+void hup_handler(int sig)
+{
+ if (verbose > 0) {
+ syslog(LOG_INFO, "--- Results after %d passes ---\n", pass);
+ status_message();
+ }
+ closelog();
+ exit(0);
+}
+
+void sigusr1_handler(int sig) {
+ verbose++;
+ syslog(LOG_INFO, "Increased verbosity to %d (increase: SIGUSR1, reset: SIGUSR2).\n", verbose);
+ status_message();
+}
+
+void sigusr2_handler(int sig) {
+ verbose = 0;
+ syslog(LOG_INFO, "Set verbosity to 0 (increase: SIGUSR1, reset: SIGUSR2).\n");
+}
+
+void sync_cycle(int fd, int interval)
+{
+ char buf[1024]; /* TODO: why 1024 and not 1000? */
+ struct timeval start;
+ struct timeval end;
+ long long usec;
+ int count = 0;
+ int i;
+ int res;
+
+ gettimeofday(&start, NULL);
+ for (i=0; i < interval*8; i++) {
+ res = read(fd, buf, sizeof(buf));
+ if (res < 0) {
+ syslog(LOG_ERR, "Failed to read from pseudo interface: %s\n", strerror(errno));
+ exit(1);
+ }
+ count += res/8;
+ }
+ gettimeofday(&end, NULL);
+
+ /* time difference in microseconds: */
+ usec = (end.tv_sec - start.tv_sec) * 1000000;
+ usec += end.tv_usec - start.tv_usec;
+
+ clock_sync(interval, usec - (count * USEC_PER_ZAP_TICK));
+
+ pass++;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int opt;
+ int interval = DEFAULT_INTERVAL;
+ int cycles_to_run = 0;
+ int i;
+
+ program = argv[0];
+ while((opt = getopt(argc, argv, "c:hi:t:v")) != -1) {
+ switch (opt) {
+ case 'h': usage(); exit(0); break;
+ case 'c': cycles_to_run = atoi(optarg); break;
+ case 'i': interval = atoi(optarg); break; /* number of seconds */
+ case 't': sync_tolerance = atoi(optarg); break; /* usec */
+ case 'v': verbose++; break;
+ default:
+ fprintf(stderr, "%s: Unknown option: %c. Aborting\n", argv[0], opt);
+ usage();
+ exit(1);
+ }
+ }
+
+ openlog(program, LOG_PERROR | LOG_PID, LOG_DAEMON);
+ fd = open("/dev/zap/pseudo", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open zap interface: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (verbose >=1)
+ syslog(LOG_INFO, "Opened pseudo zap interface, measuring accuracy...\n");
+
+ signal(SIGHUP, hup_handler);
+ signal(SIGINT, hup_handler);
+ signal(SIGUSR1, sigusr1_handler);
+ signal(SIGUSR2, sigusr2_handler);
+
+ if (cycles_to_run > 0) {
+ for(i=0; i<cycles_to_run; i++) {
+ sync_cycle(fd, interval);
+ }
+ hup_handler(0); /* exit */;
+ }
+
+ /* else (option -c not provided): run forever. */
+ for(;;) {
+ sync_cycle(fd, interval);
+ }
+}
Propchange: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/tzafrir/xpp_1.2/xpp/utils/adj_clock.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the zaptel-commits
mailing list