diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2011-10-01 18:26:31 -0400 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2011-10-01 18:26:31 -0400 |
commit | 282122c022d42765b491a11ced84b1749469c726 (patch) | |
tree | 9073a8a76bfd266aa7b23590ae24ab2aa644e6bd /gpsd.php.in | |
parent | a98e65e54178c39d6b15d64f87c9c560149bbac5 (diff) | |
download | gpsd-282122c022d42765b491a11ced84b1749469c726.tar.gz |
Factor out or remove URLs. No code changes yet except in gpsd.php (now .in).
This was the easy part. Remaining removals will require more decisions.
Diffstat (limited to 'gpsd.php.in')
-rw-r--r-- | gpsd.php.in | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/gpsd.php.in b/gpsd.php.in new file mode 100644 index 00000000..ea0466f6 --- /dev/null +++ b/gpsd.php.in @@ -0,0 +1,596 @@ +<?php + +# Copyright (c) 2006,2010 Chris Kuethe <chris.kuethe@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +global $head, $blurb, $title, $googlemap, $autorefresh, $footer, $gmap_key; +global $server, $advertise, $port, $open, $swap_ew, $testmode; +$testmode = 1; # leave this set to 1 + +# Public script parameters: +# host: host name or address where GPSd runs. Default: from config file +# port: port of GPSd. Default: from config file +# op=view: show just the skyview image instead of the whole HTML page +# sz=small: used with op=view, display a small (240x240px) skyview +# op=json: respond with the GPSd POLL JSON structure +# jsonp=prefix: used with op=json, wrap the POLL JSON in parentheses +# and prepend prefix + +# If you're running PHP with the Suhosin patch (like the Debian PHP5 package), +# it may be necessary to increase the value of the +# suhosin.get.max_value_length parameter to 2048. The imgdata parameter used +# for displaying the skyview is longer than the default 512 allowed by Suhosin. +# Debian has the config file at /etc/php5/conf.d/suhosin.ini. + +# this script shouldn't take more than a few seconds to run +set_time_limit(3); +ini_set('max_execution_time', 3); + +if (!file_exists("gpsd_config.inc")) + write_config(); + +require_once("gpsd_config.inc"); + +# sample data +$resp = <<<EOF +{"class":"POLL","time":"2010-04-05T21:27:54.84Z","active":1, + "tpv":[{"class":"TPV","tag":"MID41","device":"/dev/ttyUSB0", + "time":1270517264.240,"ept":0.005,"lat":40.035093060, + "lon":-75.519748733,"alt":31.1,"track":99.4319, + "speed":0.123,"mode":3}], + "sky":[{"class":"SKY","tag":"MID41","device":"/dev/ttyUSB0", + "time":"2010-04-05T21:27:44.84Z","hdop":9.20,"vdop":12.1, + "satellites":[{"PRN":16,"el":55,"az":42,"ss":36,"used":true}, + {"PRN":19,"el":25,"az":177,"ss":0,"used":false}, + {"PRN":7,"el":13,"az":295,"ss":0,"used":false}, + {"PRN":6,"el":56,"az":135,"ss":32,"used":true}, + {"PRN":13,"el":47,"az":304,"ss":0,"used":false}, + {"PRN":23,"el":66,"az":259,"ss":40,"used":true}, + {"PRN":20,"el":7,"az":226,"ss":0,"used":false}, + {"PRN":3,"el":52,"az":163,"ss":32,"used":true}, + {"PRN":31,"el":16,"az":102,"ss":0,"used":false} + ] + } + ] +} +EOF; + + + +# if we're passing in a query, let's unpack and use it +$op = isset($_GET['op']) ? $_GET['op'] : ''; +if (isset($_GET['imgdata']) && $op == 'view'){ + $resp = base64_decode($_GET['imgdata']); + if ($resp){ + gen_image($resp); + exit(0); + } +} else { + if (isset($_GET['host'])) + if (!preg_match('/[^a-zA-Z0-9\.-]/', $_GET['host'])) + $server = $_GET['host']; + + if (isset($_GET['port'])) + if (!preg_match('/\D/', $_GET['port']) && ($port>0) && ($port<65536)) + $port = $_GET['port']; + + if ($testmode){ + $sock = @fsockopen($server, $port, $errno, $errstr, 2); + @fwrite($sock, "?POLL;\n"); + for($tries = 0; $tries < 10; $tries++){ + $resp = @fread($sock, 1536); # SKY can be pretty big + if (preg_match('/{"class":"POLL".+}/i', $resp, $m)){ + $resp = $m[0]; + break; + } + } + @fclose($sock); + if (!$resp) + $resp = '{"class":"ERROR","message":"no response from GPS daemon"}'; + } +} + +if ($op == 'view') + gen_image($resp); +else if ($op == 'json') + write_json($resp); +else + write_html($resp); + +exit(0); + +########################################################################### +function colorsetup($im){ + $C['white'] = imageColorAllocate($im, 255, 255, 255); + $C['ltgray'] = imageColorAllocate($im, 191, 191, 191); + $C['mdgray'] = imageColorAllocate($im, 127, 127, 127); + $C['dkgray'] = imageColorAllocate($im, 63, 63, 63); + $C['black'] = imageColorAllocate($im, 0, 0, 0); + $C['red'] = imageColorAllocate($im, 255, 0, 0); + $C['brightgreen'] = imageColorAllocate($im, 0, 255, 0); + $C['darkgreen'] = imageColorAllocate($im, 0, 192, 0); + $C['blue'] = imageColorAllocate($im, 0, 0, 255); + $C['cyan'] = imageColorAllocate($im, 0, 255, 255); + $C['magenta'] = imageColorAllocate($im, 255, 0, 255); + $C['yellow'] = imageColorAllocate($im, 255, 255, 0); + $C['orange'] = imageColorAllocate($im, 255, 128, 0); + + return $C; +} + +function legend($im, $sz, $C){ + $r = 30; + $fn = 5; + $x = $sz - (4*$r+7) - 2; + $y = $sz - $r - 3; + + imageFilledRectangle($im, $x, $y, $x + 4*$r + 7, $y + $r +1, $C['dkgray']); + imageRectangle($im, $x+0*$r+1, $y+1, $x + 1*$r + 0, $y + $r, $C['red']); + imageRectangle($im, $x+1*$r+2, $y+1, $x + 2*$r + 2, $y + $r, $C['yellow']); + imageRectangle($im, $x+2*$r+4, $y+1, $x + 3*$r + 4, $y + $r, $C['darkgreen']); + imageRectangle($im, $x+4*$r+6, $y+1, $x + 3*$r + 6, $y + $r, $C['brightgreen']); + imageString($im, $fn, $x+3+0*$r, $y+$r/3, "<30", $C['red']); + imageString($im, $fn, $x+5+1*$r, $y+$r/3, "30+", $C['yellow']); + imageString($im, $fn, $x+7+2*$r, $y+$r/3, "35+", $C['darkgreen']); + imageString($im, $fn, $x+9+3*$r, $y+$r/3, "40+", $C['brightgreen']); +} + +function radial($angle, $sz){ + #turn into radians + $angle = deg2rad($angle); + + # determine length of radius + $r = $sz * 0.5 * 0.95; + + # and convert length/azimuth to cartesian + $x0 = sprintf("%d", (($sz * 0.5) - ($r * cos($angle)))); + $y0 = sprintf("%d", (($sz * 0.5) - ($r * sin($angle)))); + $x1 = sprintf("%d", (($sz * 0.5) + ($r * cos($angle)))); + $y1 = sprintf("%d", (($sz * 0.5) + ($r * sin($angle)))); + + return array($x0, $y0, $x1, $y1); +} + +function azel2xy($az, $el, $sz){ + global $swap_ew; + #rotate coords... 90deg W = 180deg trig + $az += 270; + + #turn into radians + $az = deg2rad($az); + + # determine length of radius + $r = $sz * 0.5 * 0.95; + $r -= ($r * ($el/90)); + + # and convert length/azimuth to cartesian + $x = sprintf("%d", (($sz * 0.5) + ($r * cos($az)))); + $y = sprintf("%d", (($sz * 0.5) + ($r * sin($az)))); + if ($swap_ew == 0) + $x = $sz - $x; + + return array($x, $y); +} + +function splot($im, $sz, $C, $e){ + if ((0 == $e['PRN']) || (0 == $e['az'] + $e['el'] + $e['ss']) || + ($e['az'] < 0) || ($e['el'] < 0)) + return; + + $color = $C['brightgreen']; + if ($e['ss'] < 40) + $color = $C['darkgreen']; + if ($e['ss'] < 35) + $color = $C['yellow']; + if ($e['ss'] < 30) + $color = $C['red']; + if ($e['el']<10) + $color = $C['blue']; + if ($e['ss'] < 10) + $color = $C['black']; + + list($x, $y) = azel2xy($e['az'], $e['el'], $sz); + + $r = 12; + if (isset($_GET['sz']) && ($_GET['sz'] == 'small')) + $r = 8; + + imageString($im, 3, $x+4, $y+4, $e['PRN'], $C['black']); + if ($e['used'] == true) + if ($e['PRN'] > 32) + imageFilledDiamond($im, $x, $y, $r, $color); + else + imageFilledArc($im, $x, $y, $r, $r, 0, 360, $color, 0); + else + if ($e['PRN'] > 32) + imageDiamond($im, $x, $y, $r, $color); + else + imageArc($im, $x, $y, $r, $r, 0, 360, $color); +} + +function imageDiamond($im, $x, $y, $r, $color){ + $t = $r/2; + # this lunacy is because imagesetthickness doesn't seem to work + $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t ); + imagepolygon($im, $vx, 4, $color); + $t--; + $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t ); + imagepolygon($im, $vx, 4, $color); + $t--; + $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t ); + imagepolygon($im, $vx, 4, $color); +} + +function imageFilledDiamond($im, $x, $y, $r, $color){ + $t = $r/2; + while($t){ + $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t ); + imagepolygon($im, $vx, 4, $color); + $t -= 0.5; + } +} + +function elevation($im, $sz, $C, $a){ + $b = 90 - $a; + $a = $sz * 0.95 * ($a/180); + imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']); + $x = $sz/2 - 16; + $y = $sz/2 - $a; + imageString($im, 2, $x, $y, $b, $C['ltgray']); +} + +function skyview($im, $sz, $C){ + global $swap_ew; + $a = 90; $a = $sz * 0.95 * ($a/180); + imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['mdgray'], 0); + imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['black']); + $x = $sz/2 - 16; $y = $sz/2 - $a; + imageString($im, 2, $x, $y, "0", $C['ltgray']); + + $a = 85; $a = $sz * 0.95 * ($a/180); + imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['white'], 0); + imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']); + imageString($im, 1, $sz/2 - 6, $sz+$a, '5', $C['black']); + $x = $sz/2 - 16; $y = $sz/2 - $a; + imageString($im, 2, $x, $y, "5", $C['ltgray']); + + for($i = 0; $i < 180; $i += 15){ + list($x0, $y0, $x1, $y1) = radial($i, $sz); + imageLine($im, $x0, $y0, $x1, $y1, $C['ltgray']); + } + + for($i = 15; $i < 90; $i += 15) + elevation($im, $sz, $C, $i); + + $x = $sz/2 - 16; $y = $sz/2 - 8; + /* imageString($im, 2, $x, $y, "90", $C['ltgray']); */ + + imageString($im, 4, $sz/2 + 4, 2 , 'N', $C['black']); + imageString($im, 4, $sz/2 + 4, $sz - 16 , 'S', $C['black']); + if ($swap_ew == 0){ + imageString($im, 4, 4 , $sz/2 + 4, 'E', $C['black']); + imageString($im, 4, $sz - 10 , $sz/2 + 4, 'W', $C['black']); + } else { + imageString($im, 4, 4 , $sz/2 + 4, 'W', $C['black']); + imageString($im, 4, $sz - 10 , $sz/2 + 4, 'E', $C['black']); + } +} + +function gen_image($resp){ + $sz = 600; + if (isset($_GET['sz']) && ($_GET['sz'] == 'small')) + $sz = 240; + + $GPS = json_decode($resp, true); + if ($GPS['class'] != "POLL"){ + die("json_decode error: $resp"); + } + + $im = imageCreate($sz, $sz); + $C = colorsetup($im); + skyview($im, $sz, $C); + if ($sz > 240) + legend($im, $sz, $C); + + for($i = 0; $i < count($GPS['sky'][0]['satellites']); $i++){ + splot($im, $sz, $C, $GPS['sky'][0]['satellites'][$i]); + } + + header("Content-type: image/png"); + imagePNG($im); + imageDestroy($im); +} + +function dfix($x, $y, $z){ + if ($x < 0){ + $x = sprintf("%f %s", -1 * $x, $z); + } else { + $x = sprintf("%f %s", $x, $y); + } + return $x; +} + +function write_html($resp){ + global $sock, $errstr, $errno, $server, $port, $head, $body, $open; + global $blurb, $title, $autorefresh, $googlemap, $gmap_key, $footer; + global $testmode, $advertise; + + $GPS = json_decode($resp, true); + if ($GPS['class'] != 'POLL'){ + die("json_decode error: $resp"); + } + + header("Content-type: text/html; charset=UTF-8"); + + global $lat, $lon; + $lat = (float)$GPS['tpv'][0]['lat']; + $lon = (float)$GPS['tpv'][0]['lon']; + $x = $server; $y = $port; + $imgdata = base64_encode($resp); + $server = $x; $port = $y; + + if ($autorefresh > 0) + $autorefresh = "<meta http-equiv='Refresh' content='$autorefresh'/>"; + else + $autorefresh = ''; + + $gmap_head = $gmap_body = $gmap_code = ''; + if ($googlemap){ + $gmap_head = gen_gmap_head(); + $gmap_body = 'onload="Load()" onunload="GUnload()"'; + $gmap_code = gen_gmap_code(); + } + $part1 = <<<EOF +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +{$head} +{$gmap_head} +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<meta http-equiv="Content-Language" content="en,en-us"/> +<title>{$title} - GPSD Test Station {$lat}, {$lon}</title> +{$autorefresh} +<style> +.warning { + color: #FF0000; +} + +.fixed { + font-family: mono-space; +} + +.caption { + text-align: left; + margin: 1ex 3em 1ex 3em; /* top right bottom left */ +} + +.administrivia { + font-size: small; + font-family: verdana, sans-serif; +} +</style> +</head> + +<body {$body} {$gmap_body}> +<center> +<table border="0"> +<tr><td align="justify"> +{$blurb} +</td> +EOF; + + if (!strlen($advertise)) + $advertise = $server; + + if ($testmode && !$sock) + $part2 = ""; + else + $part2 = <<<EOF +<!-- ------------------------------------------------------------ --> + +<td rowspan="4" align="center" valign="top"> +<img src="?op=view&imgdata={$imgdata}" +width="600" height="600"/> +<br clear="all"/> +<p class="caption">A filled circle means the satellite was used in +the last fix. Green-yellow-red colors indicate signal strength in dB, +green=most and red=least. Diamonds indicate SBAS satellites.</p> +{$gmap_code}</td> +</tr> +EOF; + + if (!$open) + $part3 = ''; + else + $part3 = <<<EOF +<!-- ------------------------------------------------------------ --> + +<tr><td align="justify">To get real-time information, connect to +<span class="fixed">telnet://{$advertise}:{$port}/</span> and type "?POLL;" +or "?WATCH={"enable":true,"raw":true}".<br/> +Use a different server:<br/> +<form method=GET action="${_SERVER['SCRIPT_NAME']}"> +<input name="host" value="{$advertise}">: +<input name="port" value="{$port}" size="5" maxlength="5"> +<input type=submit value="Get Position"><input type=reset></form> +<br/> +</td> +</tr> +EOF; + + if ($testmode && !$sock) + $part4 = "<tr><td class='warning'>The gpsd instance that this page monitors is not running.</td></tr>"; + else { + $fix = $GPS['tpv'][0]; + $sky = $GPS['sky'][0]; + $sats = $sky['satellites']; + + $nsv = count($sats); + $ts = $fix['time']; + $sat = ''; + foreach($sats as $s) + $sat .= sprintf( + "\t<tr><td>%d</td><td>%d</td><td>%d</td><td>%d</td><td>%s</td></tr>\n", + $s['PRN'], $s['el'], $s['az'], $s['ss'], $s['used'] ? 'Y' : 'N' + ); + $part4 = <<<EOF +<!-- ------------------------------------------------------------ --> +<tr><td align=center valign=top> + <table border=1> + <tr><th colspan=2 align=center>Current Information</th></tr> + <tr><td>Time (UTC)</td><td>{$ts}</td></tr> + <tr><td>Latitude</td><td>{$fix['lat']}</td></tr> + <tr><td>Longitude</td><td>{$fix['lon']}</td></tr> + <tr><td>Altitude</td><td>{$fix['alt']}</td></tr> + <tr><td>Fix Type</td><td>{$fix['mode']}</td></tr> + <tr><td>Satellites</td><td>{$nsv}</td></tr> + <tr><td>HDOP</td><td>{$sky['hdop']}</td></tr> + <tr><td>VDOP</td><td>{$sky['vdop']}</td></tr> + </table> + <br/> + <table border=1> + <tr><th colspan=5 align=center>Current Satellites</th></tr> + <tr><th>PRN</th><th>Elevation</th><th>Azimuth</th><th>SS</th><th>Used</th></tr> +$sat </table> +</td></tr> + +<!-- raw response: +{$resp} +--> +EOF; + } + + $part5 = <<<EOF + +</table> +</center> +{$footer} +<hr/> +<p class="administrivia">This script is distributed by the +<a href="@WEBSITE@">GPSD project</a>.</p> + +</body> +</html> +EOF; + +print $part1 . $part2 . $part3 . $part4 . $part5; + +} + +function write_json($resp){ + header('Content-Type: text/javascript'); + if (isset($_GET['jsonp'])) + print "{$_GET['jsonp']}({$resp})"; + else + print $resp; +} + +function write_config(){ + $f = fopen("gpsd_config.inc", "a"); + if (!$f) + die("can't generate prototype config file. try running this script as root in DOCUMENT_ROOT"); + + $buf = <<<EOB +<?PHP +\$title = 'My GPS Server'; +\$server = 'localhost'; +#\$advertise = 'localhost'; +\$port = 2947; +\$autorefresh = 0; # number of seconds after which to refresh +\$googlemap = 0; # set to 1 if you want to have a google map +\$gmap_key = 'GetYourOwnGoogleKey'; # your google API key goes here +\$swap_ew = 0; # set to 1 if you don't understand projections +\$open = 0; # set to 1 to show the form to change the GPSd server + +## You can read the header, footer and blurb from a file... +# \$head = file_get_contents('/path/to/header.inc'); +# \$body = file_get_contents('/path/to/body.inc'); +# \$footer = file_get_contents('/path/to/footer.hinc'); +# \$blurb = file_get_contents('/path/to/blurb.inc'); + +## ... or you can just define them here +\$head = ''; +\$body = ''; +\$footer = ''; +\$blurb = <<<EOT +This is a +<a href="@WEBSITE@">gpsd</a> +server <blink><font color="red">located someplace</font></blink>. + +The hardware is a +<blink><font color="red">hardware description and link</font></blink>. + +This machine is maintained by +<a href="mailto:you@example.com">Your Name Goes Here</a>.<br/> +EOT; + +?> + +EOB; + fwrite($f, $buf); + fclose($f); +} + +function gen_gmap_head() { +global $gmap_key; +return <<<EOT +<script src="http://maps.google.com/maps?file=api&v=2&key={$gmap_key}" type="text/javascript"></script> +<script type="text/javascript"> +<!-- +// Create a base icon for all of our markers that specifies the shadow, icon +// dimensions, etc. +function Load() { + if (GBrowserIsCompatible()) { + var map = new GMap2(document.getElementById("map")); + var point = new GLatLng( {$GLOBALS['lat']}, {$GLOBALS['lon']} ); + map.setCenter( point, 14); + map.addControl(new GLargeMapControl()); + map.addControl(new GMapTypeControl()); + + var baseIcon = new GIcon(); + baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png"; + baseIcon.iconSize = new GSize(20, 34); + baseIcon.shadowSize = new GSize(37, 34); + baseIcon.iconAnchor = new GPoint(9, 34); + baseIcon.infoWindowAnchor = new GPoint(9, 2); + baseIcon.infoShadowAnchor = new GPoint(18, 25); + + var icon = new GIcon(baseIcon); + icon.image = "http://www.google.com/mapfiles/marker.png"; + var marker = new GMarker(point, icon); + map.addOverlay(marker); + } +} +--> +</script> +EOT; + +} + +function gen_gmap_code() { +return <<<EOT +<br/> +<div id="map" style="width: 550px; height: 400px; border:1px; border-style: solid;"> + Loading... + <noscript> + <span class='warning'>Sorry: you must enable javascript to view our maps.</span><br/> + </noscript> +</div> + +EOT; +} + +?> |