summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjim-p <jimp@pfsense.org>2012-08-21 16:22:31 -0400
committerjim-p <jimp@pfsense.org>2012-08-21 16:23:33 -0400
commit5c8843d5fb080c196c0d9dfcfeb526afa3cba23d (patch)
tree8edd85eebfcb94574f0151eb6df45ffb5997df75
parent73815007a4bfa41d0e7225d59c450ec853024e29 (diff)
downloadpfsense-5c8843d5fb080c196c0d9dfcfeb526afa3cba23d.zip
pfsense-5c8843d5fb080c196c0d9dfcfeb526afa3cba23d.tar.gz
Teach ntpd how to get its time from a local GPS on serial.
-rw-r--r--etc/inc/system.inc61
-rw-r--r--usr/local/www/services_ntpd.php35
-rw-r--r--usr/local/www/status_ntpd.php34
3 files changed, 127 insertions, 3 deletions
diff --git a/etc/inc/system.inc b/etc/inc/system.inc
index 811c036..9ed8f72 100644
--- a/etc/inc/system.inc
+++ b/etc/inc/system.inc
@@ -1235,21 +1235,82 @@ function system_timezone_configure() {
echo gettext("done.") . "\n";
}
+function system_ntp_setup_gps($serialport) {
+ global $g;
+ $gps_device = '/dev/gps0';
+ $serialport = '/dev/'.$serialport;
+
+ if (!file_exists($serialport))
+ return false;
+
+ conf_mount_rw();
+ // Create symlink that ntpd requires
+ unlink_if_exists($gps_device);
+ symlink($serialport, $gps_device);
+
+ /* Send the following to the GPS port to initialize the GPS */
+ $gps_init = <<<EOF
+\$PUBX,40,GSV,0,0,0,0*59
+\$PUBX,40,GLL,0,0,0,0*5C
+\$PUBX,40,ZDA,0,0,0,0*44
+\$PUBX,40,VTG,0,0,0,0*5E
+\$PUBX,40,GSV,0,0,0,0*59
+\$PUBX,40,GSA,0,0,0,0*4E
+\$PUBX,40,GGA,0,0,0,0
+\$PUBX,40,TXT,0,0,0,0
+\$PUBX,40,RMC,0,0,0,0*46
+\$PUBX,41,1,0007,0003,4800,0
+\$PUBX,40,ZDA,1,1,1,1
+EOF;
+ file_put_contents("{$g['tmp_path']}/gps.init", $gps_init);
+ `cat {$g['tmp_path']}/gps.init > $serialport`;
+
+ /* Add /etc/remote entry in case we need to read from the GPS with tip */
+ if (intval(`grep -c '^gps0' /etc/remote`) == 0)
+ `echo "gps0:dv={$serialport}:br#4800:pa=none:" >> /etc/remote`;
+
+ conf_mount_ro();
+
+ return true;
+}
+
function system_ntp_configure($start_ntpd=true) {
global $config, $g;
$driftfile = "/var/db/ntpd.drift";
+ $statsdir = "/var/log/ntp";
+ $gps_device = '/dev/gps0';
if ($g['platform'] == 'jail')
return;
+ safe_mkdir($statsdir);
+
$ntpcfg = "# \n";
$ntpcfg .= "# pfSense ntp configuration file \n";
$ntpcfg .= "# \n\n";
+ if (!empty($config['ntpd']['gpsport'])
+ && file_exists('/dev/'.$config['ntpd']['gpsport'])
+ && file_exists($gps_device)
+ && system_ntp_setup_gps($config['ntpd']['gpsport'])) {
+ $ntpcfg .= "# GPS Setup\n";
+ $ntpcfg .= "server 127.127.20.0 mode 0 minpoll 4 maxpoll 4 prefer\n";
+ $ntpcfg .= "fudge 127.127.20.0 time1 0.155 time2 0.000 flag1 1 flag2 0 flag3 1\n";
+ // Fall back to local clock if GPS is out of sync?
+ $ntpcfg .= "server 127.127.1.0\n";
+ $ntpcfg .= "fudge 127.127.1.0 stratum 12\n";
+ }
+
+ $ntpcfg .= "\n\n# Upstream Servers\n";
/* foreach through servers and write out to ntpd.conf */
foreach (explode(' ', $config['system']['timeservers']) as $ts)
$ntpcfg .= "server {$ts} iburst maxpoll 9\n";
+ $ntpcfg .= "enable monitor\n";
+ $ntpcfg .= "enable statistics\n";
+ $ntpcfg .= "enable clockstats\n";
+ $ntpcfg .= "statsdir {$statsdir}\n";
+ $ntpcfg .= "logconfig =syncall +clockall\n";
$ntpcfg .= "driftfile {$driftfile}\n";
if (empty($config['ntpd']['interface']))
diff --git a/usr/local/www/services_ntpd.php b/usr/local/www/services_ntpd.php
index 0cbaf2a..1aa53fb 100644
--- a/usr/local/www/services_ntpd.php
+++ b/usr/local/www/services_ntpd.php
@@ -59,6 +59,11 @@ if ($_POST) {
elseif (isset($config['ntpd']['interface']))
unset($config['ntpd']['interface']);
+ if (!empty($_POST['gpsport']) && file_exists('/dev/'.$_POST['gpsport']))
+ $config['ntpd']['gpsport'] = $_POST['gpsport'];
+ else
+ unset($config['ntpd']['gpsport']);
+
write_config("Updated NTP Server Settings");
$retval = 0;
@@ -110,12 +115,36 @@ include("head.inc");
echo ">{$ifacename}</option>\n";
} ?>
</select>
- <br/>Interfaces without an IP address will not be shown.
<br/>
- <br/>Selecting no interfaces will listen on all interfaces with a wildcard.
- <br/>Selecting all interfaces will explicitly listen on only the interfaces/IPs specified.
+ <br/><?php echo gettext("Interfaces without an IP address will not be shown."); ?>
+ <br/>
+ <br/><?php echo gettext("Selecting no interfaces will listen on all interfaces with a wildcard."); ?>
+ <br/><?php echo gettext("Selecting all interfaces will explicitly listen on only the interfaces/IPs specified."); ?>
+ </td>
+</tr>
+<?php /* Probing would be nice, but much more complex. Would need to listen to each port for 1s+ and watch for strings. */ ?>
+<?php $serialports = glob("/dev/cua?[0-9]{,.[0-9]}", GLOB_BRACE); ?>
+<?php if (!empty($serialports)): ?>
+<tr>
+ <td width="22%" valign="top" class="vncellreq">Serial GPS</td>
+ <td width="78%" class="vtable">
+ <select name="gpsport">
+ <option value="">none</option>
+ <?php foreach ($serialports as $port):
+ $shortport = substr($port,5);
+ $selected = ($shortport == $config['ntpd']['gpsport']) ? " selected" : "";?>
+ <option value="<?php echo $shortport;?>"<?php echo $selected;?>><?php echo $shortport;?></option>
+ <?php endforeach; ?>
+ </select>
+ <br/>
+ <br/><?php echo gettext("The GPS must provide NEMA format output!"); ?>
+ <br/>
+ <br/><?php echo gettext("All serial ports are listed, be sure to pick only the port with the GPS attached."); ?>
+ <br/>
+ <br/><?php echo gettext("It is best to configure at least 2 servers under"); ?> <a href="system.php"><?php echo gettext("System > General"); ?></a> <?php echo gettext("to avoid loss of sync if the GPS data is not valid over time. Otherwise ntpd may only use values from the unsynchronized local clock when proving time to clients."); ?>
</td>
</tr>
+<?php endif; ?>
<tr>
<td width="22%" valign="top">&nbsp;</td>
<td width="78%">
diff --git a/usr/local/www/status_ntpd.php b/usr/local/www/status_ntpd.php
index 9aa6039..2b9ac72 100644
--- a/usr/local/www/status_ntpd.php
+++ b/usr/local/www/status_ntpd.php
@@ -43,6 +43,7 @@
require_once("guiconfig.inc");
exec("/usr/local/bin/ntpq -pn | /usr/bin/tail +3", $ntpq_output);
+
$ntpq_servers = array();
foreach ($ntpq_output as $line) {
$server = array();
@@ -91,6 +92,20 @@ foreach ($ntpq_output as $line) {
$ntpq_servers[] = $server;
}
+exec("/usr/local/bin/ntpq -c clockvar", $ntpq_clockvar_output);
+foreach ($ntpq_clockvar_output as $line) {
+ if (substr($line, 0, 9) == "timecode=") {
+ $tmp = explode('"', $line);
+ $tmp = $tmp[1];
+ if (substr($tmp, 0, 6) == '$GPRMC') {
+ $gps_vars = explode(",", $tmp);
+ $gps_ok = ($gps_vars[2] == "A");
+ $gps_lat = $gps_vars[3] / 100.0 . $gps_vars[4];
+ $gps_lon = $gps_vars[5] / 100.0 . $gps_vars[6];
+ }
+ }
+}
+
$pgtitle = array(gettext("Status"),gettext("NTP"));
$shortcut_section = "ntp";
include("head.inc");
@@ -163,6 +178,25 @@ include("head.inc");
<?php $i++; endforeach; endif; ?>
</tbody>
</table>
+<?php if (($gps_ok) && ($gps_lat) && ($gps_lon)): ?>
+ <table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
+ <thead>
+ <tr>
+ <th class="listhdrr"><?=gettext("Clock Latitude"); ?></th>
+ <th class="listhdrr"><?=gettext("Clock Longitude"); ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="listlr" align="center"><?php echo $gps_lat; ?></td>
+ <td class="listlr" align="center"><?php echo $gps_lon; ?></td>
+ </tr>
+ <tr>
+ <td class="listlr" colspan="2" align="center"><a href="http://maps.google.com/?q=<?php echo $gps_lat; ?>,<?php echo $gps_lon; ?>">Google Maps Link</a></td>
+ </tr>
+ </tbody>
+ </table>
+<?php endif; ?>
</div></td></tr>
</table>
<?php include("fend.inc"); ?>
OpenPOWER on IntegriCloud