first show lad
[rb-clock.git] / php / gpsd / gpsd.php
1 <?php
2
3 # @MASTER@
4
5 # Copyright (c) 2006,2010 Chris Kuethe <chris.kuethe@gmail.com>
6 #
7 # Permission to use, copy, modify, and distribute this software for any
8 # purpose with or without fee is hereby granted, provided that the above
9 # copyright notice and this permission notice appear in all copies.
10 #
11 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 # Changed to Google Maps API v3, requires no API key, and shorter code
20 # Sanjeev Gupta <ghane0@gmail.com> 2013-01-05
21
22 global $head, $blurb, $title, $showmap, $autorefresh, $footer, $gmap_key;
23 global $server, $advertise, $port, $open, $swap_ew, $testmode;
24 $testmode = 1; # leave this set to 1
25
26 # Public script parameters:
27 #   host: host name or address where GPSd runs. Default: from config file
28 #   port: port of GPSd. Default: from config file
29 #   op=view: show just the skyview image instead of the whole HTML page
30 #     sz=small: used with op=view, display a small (240x240px) skyview
31 #   op=json: respond with the GPSd POLL JSON structure
32 #     jsonp=prefix: used with op=json, wrap the POLL JSON in parentheses
33 #                   and prepend prefix
34
35 # If you're running PHP with the Suhosin patch (like the Debian PHP5 package),
36 # it may be necessary to increase the value of the
37 # suhosin.get.max_value_length parameter to 2048. The imgdata parameter used
38 # for displaying the skyview is longer than the default 512 allowed by Suhosin.
39 # Debian has the config file at /etc/php5/conf.d/suhosin.ini.
40
41 # this script shouldn't take more than a few seconds to run
42 set_time_limit(3);
43 ini_set('max_execution_time', 3);
44
45 if (!file_exists("gpsd_config.inc"))
46         write_config();
47
48 require_once("gpsd_config.inc");
49
50 # sample data
51 $resp = <<<EOF
52 {"class":"POLL","time":"2010-04-05T21:27:54.84Z","active":1,
53  "tpv":[{"class":"TPV","tag":"MID41","device":"/dev/ttyUSB0",
54            "time":1270517264.240,"ept":0.005,"lat":40.035093060,
55            "lon":-75.519748733,"alt":31.1,"track":99.4319,
56            "speed":0.123,"mode":3}],
57  "sky":[{"class":"SKY","tag":"MID41","device":"/dev/ttyUSB0",
58               "time":"2010-04-05T21:27:44.84Z","hdop":9.20,"vdop":12.1,
59               "satellites":[{"PRN":16,"el":55,"az":42,"ss":36,"used":true},
60                             {"PRN":19,"el":25,"az":177,"ss":0,"used":false},
61                             {"PRN":7,"el":13,"az":295,"ss":0,"used":false},
62                             {"PRN":6,"el":56,"az":135,"ss":32,"used":true},
63                             {"PRN":13,"el":47,"az":304,"ss":0,"used":false},
64                             {"PRN":23,"el":66,"az":259,"ss":40,"used":true},
65                             {"PRN":20,"el":7,"az":226,"ss":0,"used":false},
66                             {"PRN":3,"el":52,"az":163,"ss":32,"used":true},
67                             {"PRN":31,"el":16,"az":102,"ss":0,"used":false}
68                            ]
69              }
70             ]
71 }
72 EOF;
73
74
75
76 # if we're passing in a query, let's unpack and use it
77 $op = isset($_GET['op']) ? $_GET['op'] : '';
78 if (isset($_GET['imgdata']) && $op == 'view'){
79         $resp = base64_decode($_GET['imgdata']);
80         if ($resp){
81                 gen_image($resp);
82                 exit(0);
83         }
84 } else {
85         if (isset($_GET['host']))
86                 if (!preg_match('/[^a-zA-Z0-9\.-]/', $_GET['host']))
87                         $server = $_GET['host'];
88
89         if (isset($_GET['port']))
90                 if (!preg_match('/\D/', $_GET['port']) && ($port>0) && ($port<65536))
91                         $port = $_GET['port'];
92
93         if ($testmode){
94                 $sock = @fsockopen($server, $port, $errno, $errstr, 2);
95                 @fwrite($sock, "?WATCH={\"enable\":true}\n");
96                 usleep(1000);
97                 @fwrite($sock, "?POLL;\n");
98                 usleep(1000);
99                 for($tries = 0; $tries < 10; $tries++){
100                         $resp = @fread($sock, 2000); # SKY can be pretty big
101                         if (preg_match('/{"class":"POLL".+}/i', $resp, $m)){
102                                 $resp = $m[0];
103                                 break;
104                         }
105                 }
106                 @fclose($sock);
107                 if (!$resp)
108                         $resp = '{"class":"ERROR","message":"no response from GPS daemon"}';
109         }
110 }
111
112 if ($op == 'view')
113         gen_image($resp);
114 else if ($op == 'json')
115         write_json($resp);
116 else
117         write_html($resp);
118
119 exit(0);
120
121 ###########################################################################
122 # Function to decide if a PRN is a true GPS bird or SBAS, GBAS, etc.
123 # Sanjeev Gupta <ghane0@gmail.com> 20150408
124 # Please refer to gps.h lines ~~ 95 , for a central definition
125 function isGPS($PRN) {
126         if ($PRN <= 32) return TRUE ;                   # Navstar GPS
127         if ($PRN >= 64 && $PRN <= 96) return TRUE ;     # GLONASS
128         if ($PRN >= 159 ) return TRUE ;                 # BeiDou ?
129         return FALSE ;                                  # SBAS, GBAS, unknown
130         }
131
132 function colorsetup($im){
133         $C['white']     = imageColorAllocate($im, 255, 255, 255);
134         $C['ltgray']    = imageColorAllocate($im, 191, 191, 191);
135         $C['mdgray']    = imageColorAllocate($im, 127, 127, 127);
136         $C['dkgray']    = imageColorAllocate($im, 63, 63, 63);
137         $C['black']     = imageColorAllocate($im, 0, 0, 0);
138         $C['red']       = imageColorAllocate($im, 255, 0, 0);
139         $C['brightgreen'] = imageColorAllocate($im, 0, 255, 0);
140         $C['darkgreen'] = imageColorAllocate($im, 0, 192, 0);
141         $C['blue']      = imageColorAllocate($im, 0, 0, 255);
142         $C['cyan']      = imageColorAllocate($im, 0, 255, 255);
143         $C['magenta']   = imageColorAllocate($im, 255, 0, 255);
144         $C['yellow']    = imageColorAllocate($im, 255, 255, 0);
145         $C['orange']    = imageColorAllocate($im, 255, 128, 0);
146
147         return $C;
148 }
149
150 function legend($im, $sz, $C){
151         $r = 30;
152         $fn = 5;
153         $x = $sz - (4*$r+7) - 2;
154         $y = $sz - $r - 3;
155
156         imageFilledRectangle($im, $x, $y, $x + 4*$r + 7, $y + $r +1, $C['dkgray']);
157         imageRectangle($im, $x+0*$r+1, $y+1, $x + 1*$r + 0, $y + $r, $C['red']);
158         imageRectangle($im, $x+1*$r+2, $y+1, $x + 2*$r + 2, $y + $r, $C['yellow']);
159         imageRectangle($im, $x+2*$r+4, $y+1, $x + 3*$r + 4, $y + $r, $C['darkgreen']);
160         imageRectangle($im, $x+4*$r+6, $y+1, $x + 3*$r + 6, $y + $r, $C['brightgreen']);
161         imageString($im, $fn, $x+3+0*$r, $y+$r/3, "<30", $C['red']);
162         imageString($im, $fn, $x+5+1*$r, $y+$r/3, "30+", $C['yellow']);
163         imageString($im, $fn, $x+7+2*$r, $y+$r/3, "35+", $C['darkgreen']);
164         imageString($im, $fn, $x+9+3*$r, $y+$r/3, "40+", $C['brightgreen']);
165 }
166
167 function radial($angle, $sz){
168         #turn into radians
169         $angle = deg2rad($angle);
170
171         # determine length of radius
172         $r = $sz * 0.5 * 0.95;
173
174         # and convert length/azimuth to cartesian
175         $x0 = sprintf("%d", (($sz * 0.5) - ($r * cos($angle))));
176         $y0 = sprintf("%d", (($sz * 0.5) - ($r * sin($angle))));
177         $x1 = sprintf("%d", (($sz * 0.5) + ($r * cos($angle))));
178         $y1 = sprintf("%d", (($sz * 0.5) + ($r * sin($angle))));
179
180         return array($x0, $y0, $x1, $y1);
181 }
182
183 function azel2xy($az, $el, $sz){
184         global $swap_ew;
185         #rotate coords... 90deg W = 180deg trig
186         $az += 270;
187
188         #turn into radians
189         $az = deg2rad($az);
190
191         # determine length of radius
192         $r = $sz * 0.5 * 0.95;
193         $r -= ($r * ($el/90));
194
195         # and convert length/azimuth to cartesian
196         $x = sprintf("%d", (($sz * 0.5) + ($r * cos($az))));
197         $y = sprintf("%d", (($sz * 0.5) + ($r * sin($az))));
198         if ($swap_ew == 0)
199                 $x = $sz - $x;
200
201         return array($x, $y);
202 }
203
204 function splot($im, $sz, $C, $e){
205         if ((0 == $e['PRN']) || (0 == $e['az'] + $e['el'] + $e['ss']) ||
206             ($e['az'] < 0) || ($e['el'] < 0))
207                 return;
208
209         $color = $C['brightgreen'];
210         if ($e['ss'] < 40)
211                 $color = $C['darkgreen'];
212         if ($e['ss'] < 35)
213                 $color = $C['yellow'];
214         if ($e['ss'] < 30)
215                 $color = $C['red'];
216         if ($e['el']<10)
217                 $color = $C['blue'];
218         if ($e['ss'] < 10)
219                 $color = $C['black'];
220
221         list($x, $y) = azel2xy($e['az'], $e['el'], $sz);
222
223         $r = 12;
224         if (isset($_GET['sz']) && ($_GET['sz'] == 'small'))
225                 $r = 8;
226
227         imageString($im, 3, $x+4, $y+4, $e['PRN'], $C['black']);
228         if ($e['used'] == true)
229                 if (isGPS($e['PRN']))
230                         imageFilledArc($im, $x, $y, $r, $r, 0, 360, $color, 0);
231                 else
232                         imageFilledDiamond($im, $x, $y, $r, $color);
233         else
234                 if (isGPS($e['PRN']))
235                         imageArc($im, $x, $y, $r, $r, 0, 360, $color);
236                 else
237                         imageDiamond($im, $x, $y, $r, $color);
238 }
239
240
241 function imageDiamond($im, $x, $y, $r, $color){
242         $t = $r/2;
243         # this lunacy is because imagesetthickness doesn't seem to work
244         $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
245         imagepolygon($im, $vx, 4, $color);
246         $t--;
247         $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
248         imagepolygon($im, $vx, 4, $color);
249         $t--;
250         $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
251         imagepolygon($im, $vx, 4, $color);
252 }
253
254 function imageFilledDiamond($im, $x, $y, $r, $color){
255         $t = $r/2;
256         while($t){
257                 $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
258                 imagepolygon($im, $vx, 4, $color);
259                 $t -= 0.5;
260         }
261 }
262
263 function elevation($im, $sz, $C, $a){
264         $b = 90 - $a;
265         $a = $sz * 0.95 * ($a/180);
266         imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']);
267         $x = $sz/2 - 16;
268         $y = $sz/2 - $a;
269         imageString($im, 2, $x, $y, $b, $C['ltgray']);
270 }
271
272 function skyview($im, $sz, $C){
273         global $swap_ew;
274         $a = 90; $a = $sz * 0.95 * ($a/180);
275         imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['mdgray'], 0);
276         imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['black']);
277         $x = $sz/2 - 16; $y = $sz/2 - $a;
278         imageString($im, 2, $x, $y, "0", $C['ltgray']);
279
280         $a = 85; $a = $sz * 0.95 * ($a/180);
281         imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['white'], 0);
282         imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']);
283         imageString($im, 1, $sz/2 - 6, $sz+$a, '5', $C['black']);
284         $x = $sz/2 - 16; $y = $sz/2 - $a;
285         imageString($im, 2, $x, $y, "5", $C['ltgray']);
286
287         for($i = 0; $i < 180; $i += 15){
288                 list($x0, $y0, $x1, $y1) = radial($i, $sz);
289                 imageLine($im, $x0, $y0, $x1, $y1, $C['ltgray']);
290         }
291
292         for($i = 15; $i < 90; $i += 15)
293                 elevation($im, $sz, $C, $i);
294
295         $x = $sz/2 - 16; $y = $sz/2 - 8;
296         /* imageString($im, 2, $x, $y, "90", $C['ltgray']); */
297
298         imageString($im, 4, $sz/2 + 4, 2        , 'N', $C['black']);
299         imageString($im, 4, $sz/2 + 4, $sz - 16 , 'S', $C['black']);
300         if ($swap_ew == 0){
301                 imageString($im, 4, 4        , $sz/2 + 4, 'E', $C['black']);
302                 imageString($im, 4, $sz - 10 , $sz/2 + 4, 'W', $C['black']);
303         } else {
304                 imageString($im, 4, 4        , $sz/2 + 4, 'W', $C['black']);
305                 imageString($im, 4, $sz - 10 , $sz/2 + 4, 'E', $C['black']);
306         }
307 }
308
309 function gen_image($resp){
310         $sz = 600;
311         if (isset($_GET['sz']) && ($_GET['sz'] == 'small'))
312                 $sz = 240;
313
314         $GPS = json_decode($resp, true);
315         if ($GPS['class'] != "POLL"){
316                 die("json_decode error: $resp");
317         }
318
319         $im = imageCreate($sz, $sz);
320         $C = colorsetup($im);
321         skyview($im, $sz, $C);
322         if ($sz > 240)
323                 legend($im, $sz, $C);
324
325         for($i = 0; $i < count($GPS['sky'][0]['satellites']); $i++){
326                 splot($im, $sz, $C, $GPS['sky'][0]['satellites'][$i]);
327         }
328
329         header("Content-type: image/png");
330         imagePNG($im);
331         imageDestroy($im);
332 }
333
334 function dfix($x, $y, $z){
335         if ($x < 0){
336                 $x = sprintf("%f %s", -1 * $x, $z);
337         } else {
338                 $x = sprintf("%f %s", $x, $y);
339         }
340         return $x;
341 }
342
343 function write_html($resp){
344         global $sock, $errstr, $errno, $server, $port, $head, $body, $open;
345         global $blurb, $title, $autorefresh, $showmap, $gmap_key, $footer;
346         global $testmode, $advertise;
347
348         $GPS = json_decode($resp, true);
349         if ($GPS['class'] != 'POLL'){
350                 die("json_decode error: $resp");
351         }
352
353         header("Content-type: text/html; charset=UTF-8");
354
355         global $lat, $lon;
356         $lat = (float)$GPS['tpv'][0]['lat'];
357         $lon = (float)$GPS['tpv'][0]['lon'];
358         $x = $server; $y = $port;
359         $imgdata = base64_encode($resp);
360         $server = $x; $port = $y;
361
362         if ($autorefresh > 0)
363                 $autorefresh = "<meta http-equiv='Refresh' content='$autorefresh'/>";
364         else
365                 $autorefresh = '';
366
367         $map_head = $map_body = $map_code = '';
368         if ($showmap == 1) {
369                 $map_head = gen_gmap_head();
370                 $map_body = 'onload="Load()" onunload="GUnload()"';
371                 $map_code = gen_map_code();
372         } else if ($showmap == 2) {
373                 $map_head = gen_osm_head();
374                 $map_body = 'onload="Load()"';
375                 $map_code = gen_map_code();
376         }
377         $part1 = <<<EOF
378 <?xml version="1.0" encoding="UTF-8"?>
379 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
380     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
381 <html xmlns="http://www.w3.org/1999/xhtml">
382 <head>
383 {$head}
384 {$map_head}
385 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
386 <meta http-equiv="Content-Language" content="en,en-us"/>
387 <title>{$title} - GPSD Test Station {$lat}, {$lon}</title>
388 {$autorefresh}
389 <style>
390 .warning {
391     color: #FF0000;
392 }
393
394 .fixed {
395     font-family: mono-space;
396 }
397
398 .caption {
399     text-align: left;
400     margin: 1ex 3em 1ex 3em; /* top right bottom left */
401 }
402
403 .administrivia {
404     font-size: small;
405     font-family: verdana, sans-serif;
406 }
407 </style>
408 </head>
409
410 <body {$body} {$map_body}>
411 <center>
412 <table border="0">
413 <tr><td align="justify">
414 {$blurb}
415 </td>
416 EOF;
417
418         if (!strlen($advertise))
419                 $advertise = $server;
420
421         if ($testmode && !$sock)
422                 $part2 = "";
423         else
424                 $part2 = <<<EOF
425 <!-- ------------------------------------------------------------ -->
426
427 <td rowspan="4" align="center" valign="top">
428 <img src="?op=view&amp;imgdata={$imgdata}"
429 width="600" height="600"/>
430 <br clear="all"/>
431 <p class="caption">A filled circle means the satellite was used in
432 the last fix. Green-yellow-red colors indicate signal strength in dB,
433 green=most and red=least.  Diamonds indicate Augmentation satellites.</p>
434 {$map_code}</td>
435 </tr>
436 EOF;
437
438         if (!$open)
439                 $part3 = '';
440         else
441                 $part3 = <<<EOF
442 <!-- ------------------------------------------------------------ -->
443
444 <tr><td align="justify">To get real-time information, connect to
445 <span class="fixed">telnet://{$advertise}:{$port}/</span> and type "?POLL;"
446 or "?WATCH={"enable":true,"raw":true}".<br/>
447 Use a different server:<br/>
448 <form method=GET action="${_SERVER['SCRIPT_NAME']}">
449 <input name="host" value="{$advertise}">:
450 <input name="port" value="{$port}" size="5" maxlength="5">
451 <input type=submit value="Get Position"><input type=reset></form>
452 <br/>
453 </td>
454 </tr>
455 EOF;
456
457         if ($testmode && !$sock)
458                 $part4 = "<tr><td class='warning'>The gpsd instance that this page monitors is not running.</td></tr>";
459         else {
460                 $fix = $GPS['tpv'][0];
461                 $sky = $GPS['sky'][0];
462                 $sats = $sky['satellites'];
463
464                 $nsv = count($sats);
465                 $ts = $fix['time'];
466                 $sat = '';
467                 foreach($sats as $s)
468                         $sat .= sprintf(
469                                 "\t<tr><td>%d</td><td>%d</td><td>%d</td><td>%d</td><td>%s</td></tr>\n",
470                                 $s['PRN'], $s['el'], $s['az'], $s['ss'], $s['used'] ? 'Y' : 'N'
471                         );
472                 $part4 = <<<EOF
473 <!-- ------------------------------------------------------------ -->
474 <tr><td align=center valign=top>
475     <table border=1>
476         <tr><th colspan=2 align=center>Current Information</th></tr>
477         <tr><td>Time (UTC)</td><td>{$ts}</td></tr>
478         <tr><td>Latitude</td><td>{$fix['lat']}</td></tr>
479         <tr><td>Longitude</td><td>{$fix['lon']}</td></tr>
480         <tr><td>Altitude</td><td>{$fix['alt']}</td></tr>
481         <tr><td>Fix Type</td><td>{$fix['mode']}</td></tr>
482         <tr><td>Satellites</td><td>{$nsv}</td></tr>
483         <tr><td>HDOP</td><td>{$sky['hdop']}</td></tr>
484         <tr><td>VDOP</td><td>{$sky['vdop']}</td></tr>
485     </table>
486     <br/>
487     <table border=1>
488         <tr><th colspan=5 align=center>Current Satellites</th></tr>
489         <tr><th>PRN</th><th>Elevation</th><th>Azimuth</th><th>SS</th><th>Used</th></tr>
490 $sat    </table>
491 </td></tr>
492
493 <!-- raw response:
494 {$resp}
495 -->
496 EOF;
497         }
498
499         $part5 = <<<EOF
500
501 </table>
502 </center>
503 {$footer}
504 <hr/>
505 <p class="administrivia">This script is distributed by the
506 <a href="@WEBSITE@">GPSD project</a>.</p>
507
508 </body>
509 </html>
510 EOF;
511
512 print $part1 . $part2 . $part3 . $part4 . $part5;
513
514 }
515
516 function write_json($resp){
517         header('Content-Type: text/javascript');
518         if (isset($_GET['jsonp']))
519                 print "{$_GET['jsonp']}({$resp})";
520         else
521                 print $resp;
522 }
523
524 function write_config(){
525         $f = fopen("gpsd_config.inc", "a");
526         if (!$f)
527                 die("can't generate prototype config file. try running this script as root in DOCUMENT_ROOT");
528
529         $buf = <<<EOB
530 <?PHP
531 \$title = 'My GPS Server';
532 \$server = 'localhost';
533 #\$advertise = 'localhost';
534 \$port = 2947;
535 \$autorefresh = 0; # number of seconds after which to refresh
536 \$showmap = 0; # set to 1 if you want to have a google map, set it to 2 if you want a map based on openstreetmap
537 \$gmap_key = 'GetYourOwnGoogleKey'; # your google API key goes here
538 \$swap_ew = 0; # set to 1 if you don't understand projections
539 \$open = 0; # set to 1 to show the form to change the GPSd server
540
541 ## You can read the header, footer and blurb from a file...
542 # \$head = file_get_contents('/path/to/header.inc');
543 # \$body = file_get_contents('/path/to/body.inc');
544 # \$footer = file_get_contents('/path/to/footer.hinc');
545 # \$blurb = file_get_contents('/path/to/blurb.inc');
546
547 ## ... or you can just define them here
548 \$head = '';
549 \$body = '';
550 \$footer = '';
551 \$blurb = <<<EOT
552 This is a
553 <a href="@WEBSITE@">gpsd</a>
554 server <blink><font color="red">located someplace</font></blink>.
555
556 The hardware is a
557 <blink><font color="red">hardware description and link</font></blink>.
558
559 This machine is maintained by
560 <a href="mailto:you@example.com">Your Name Goes Here</a>.<br/>
561 EOT;
562
563 ?>
564
565 EOB;
566         fwrite($f, $buf);
567         fclose($f);
568 }
569
570 function gen_gmap_head() {
571 global $gmap_key;
572 return <<<EOT
573 <script src="//maps.googleapis.com/maps/api/js?sensor=false"
574         type="text/javascript">
575 </script>
576
577 <script type="text/javascript">
578  <!--
579     function Load() {
580       var map = new google.maps.Map(
581         document.getElementById('map'), {
582           center: new google.maps.LatLng({$GLOBALS['lat']}, {$GLOBALS['lon']}),
583           zoom: 13,
584           mapTypeId: google.maps.MapTypeId.ROADMAP
585       });
586
587       var marker = new google.maps.Marker({
588             position: new google.maps.LatLng({$GLOBALS['lat']}, {$GLOBALS['lon']}),
589             map: map
590       });
591
592     }
593     google.maps.event.addDomListener(window, 'load', initialize);
594
595  -->
596 </script>
597 EOT;
598 }
599
600 function gen_osm_head() {
601 global $GPS;
602 return <<<EOT
603 <script src="http://openlayers.org/api/OpenLayers.js" type="text/javascript"></script>
604 <script type="text/javascript">
605     <!--
606 function Load() {
607         document.getElementById("map").firstChild.data = "";
608         var map = new OpenLayers.Map("map", {
609                 controls: [
610                         new OpenLayers.Control.Navigation(),
611                         new OpenLayers.Control.PanZoomBar(),
612                         new OpenLayers.Control.ScaleLine(),
613                         new OpenLayers.Control.LayerSwitcher()
614                 ]
615         });
616         var layer = new OpenLayers.Layer.OSM("Open Street Map");
617         map.addLayer(layer);
618
619         var center = new OpenLayers.LonLat({$GLOBALS['lon']}, {$GLOBALS['lat']})
620                 .transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
621         map.setCenter(center, 12);
622
623         var markers = new OpenLayers.Layer.Markers("Markers");
624         markers.addMarker(new OpenLayers.Marker(center));
625         map.addLayer(markers);
626 }
627     -->
628     </script>
629 EOT;
630 }
631
632 function gen_map_code() {
633 return <<<EOT
634 <br/>
635 <div id="map" style="width: 550px; height: 400px; border:1px; border-style: solid;">
636     Loading...
637     <noscript>
638         <span class='warning'>Sorry: you must enable javascript to view our maps.</span><br/>
639     </noscript>
640 </div>
641
642 EOT;
643 }
644
645 ?>