skyview.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. <?php
  2. # Copyright (c) 2006,2007 Chris Kuethe <chris.kuethe@gmail.com>
  3. # Updated 2015 by Sanjeev Gupta <ghane0@gmail.com>
  4. #
  5. # This file is Copyright (c) 2010-2019 by the GPSD project
  6. # SPDX-License-Identifier: BSD-2-clause
  7. // This program originally read a logfile of filtered gpsd messages,
  8. // type Y. The gpsd protocal changed in 2.90, since when this became
  9. // non-functional.
  10. //
  11. // The program has been updated (the first while loop) to read messages
  12. // over tcp; of type SKY. These are unpacked from JSON. No attempt has
  13. // been made to touch the actual calculation or plotting routines.
  14. //
  15. // Because it now reads a live stream, the program must be run with an
  16. // option, "count", to specify the number of SKY messages it reads. SKY
  17. // messages are usually emitted every 5 secs, so a number close to 700
  18. // will cover an hour's worth.
  19. //
  20. // Tested to work with php5.6 , although earlier versions may work.
  21. $cellmode = 0;
  22. if ($argc != 3){
  23. if (($argc != 4) || strcmp("cells", $argv[3])){
  24. die("usage: ${argv[0]} count imagefile.png [cells]\n");
  25. } else {
  26. $cellmode = 1;
  27. }
  28. }
  29. // How many samples to read of SKY messages.
  30. $count = $argv[1] ;
  31. $sz = 640;
  32. $cellsize = 5; # degrees
  33. $radius = 8; # pixels
  34. $filled = 0;
  35. $im = imageCreate($sz, $sz);
  36. $C = colorsetup($im);
  37. skyview($im, $sz, $C);
  38. legend($im, $sz, $C);
  39. $sky = array();
  40. error_reporting(E_ALL);
  41. // Get the port for the GPSD service.
  42. $service_port = 2947 ;
  43. // Get the IP address for the target host.
  44. $address = "127.0.0.1" ;
  45. // Create a TCP/IP socket.
  46. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  47. if ($socket === false) {
  48. echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
  49. }
  50. $result = socket_connect($socket, $address, $service_port);
  51. if ($result === false) {
  52. echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
  53. }
  54. // Send a WATCH command.
  55. $cmd = "?WATCH={\"enable\":true,\"json\":true};" ;
  56. socket_write($socket, $cmd, strlen($in));
  57. // Start the loop to start reading from gpsd.
  58. $out = '';
  59. $j = 0 ;
  60. while (($out = socket_read($socket, 2048)) && ( $j < $count) ) {
  61. if (strpos($out, "SKY")) {
  62. $j = $j + 1;
  63. $PRN = json_decode($out,true);
  64. // var_dump($PRN) ;
  65. // object(stdClass)#12 (5)
  66. // ["PRN"]=>
  67. // int(137)
  68. // ["el"]=>
  69. // int(42)
  70. // ["az"]=>
  71. // int(91)
  72. // ["ss"]=>
  73. // int(32)
  74. // ["used"]=>
  75. // bool(false)
  76. $n = count($PRN["satellites"]) ;
  77. for($i = 0; $i < $n; $i++) {
  78. $sv = $PRN["satellites"][$i]["PRN"] ;
  79. $el = $PRN["satellites"][$i]["el"] ;
  80. $az = $PRN["satellites"][$i]["az"] ;
  81. $snr = $PRN["satellites"][$i]["ss"] ;
  82. $u = $PRN["satellites"][$i]["used"] ;
  83. // Below this, Chris' original code, more or less. -- Sanjeev 20150326
  84. if ($cellmode){
  85. $az = $cellsize * (int)($az/$cellsize);
  86. $el = $cellsize * (int)($el/$cellsize);
  87. }
  88. if (isset($sky[$az][$el]['avg'])){
  89. $sky[$az][$el]['snr'] += $snr;
  90. $sky[$az][$el]['num']++;
  91. } else {
  92. $sky[$az][$el]['snr'] = $snr;
  93. $sky[$az][$el]['num'] = 1;
  94. }
  95. $sky[$az][$el]['avg'] = $sky[$az][$el]['snr'] / $sky[$az][$el]['num'];
  96. }
  97. }
  98. }
  99. foreach($sky as $az => $x){
  100. foreach ($sky[$az] as $el => $y){
  101. $e = array(-1, $el, $az, $sky[$az][$el]['avg'], -1);
  102. if ($cellmode)
  103. cellplot($im, $sz, $C, $cellsize, $e);
  104. else
  105. splot($im, $sz, $C, $radius, $filled, $e);
  106. }
  107. }
  108. skygrid($im, $sz, $C); # redraw grid over satellites
  109. imagePNG($im, $argv[2]);
  110. imageDestroy($im);
  111. exit(0);
  112. ###########################################################################
  113. function colorsetup($im){
  114. $C['white'] = imageColorAllocate($im, 255, 255, 255);
  115. $C['ltgray'] = imageColorAllocate($im, 191, 191, 191);
  116. $C['mdgray'] = imageColorAllocate($im, 127, 127, 127);
  117. $C['dkgray'] = imageColorAllocate($im, 63, 63, 63);
  118. $C['black'] = imageColorAllocate($im, 0, 0, 0);
  119. $C['red'] = imageColorAllocate($im, 255, 0, 0);
  120. $C['brightgreen'] = imageColorAllocate($im, 0, 255, 0);
  121. $C['darkgreen'] = imageColorAllocate($im, 0, 192, 0);
  122. $C['blue'] = imageColorAllocate($im, 0, 0, 255);
  123. $C['cyan'] = imageColorAllocate($im, 0, 255, 255);
  124. $C['magenta'] = imageColorAllocate($im, 255, 0, 255);
  125. $C['yellow'] = imageColorAllocate($im, 255, 255, 0);
  126. $C['orange'] = imageColorAllocate($im, 255, 128, 0);
  127. return $C;
  128. }
  129. function legend($im, $sz, $C){
  130. $r = 30;
  131. $fn = 5;
  132. $x = $sz - (4*$r+7) - 2;
  133. $y = $sz - $r - 3;
  134. imageFilledRectangle($im, $x, $y, $x + 4*$r + 7, $y + $r +1, $C['dkgray']);
  135. imageRectangle($im, $x+0*$r+1, $y+1, $x + 1*$r + 0, $y + $r, $C['red']);
  136. imageRectangle($im, $x+1*$r+2, $y+1, $x + 2*$r + 2, $y + $r, $C['yellow']);
  137. imageRectangle($im, $x+2*$r+4, $y+1, $x + 3*$r + 4, $y + $r, $C['darkgreen']);
  138. imageRectangle($im, $x+4*$r+6, $y+1, $x + 3*$r + 6, $y + $r, $C['brightgreen']);
  139. imageString($im, $fn, $x+3+0*$r, $y+$r/3, "<30", $C['red']);
  140. imageString($im, $fn, $x+5+1*$r, $y+$r/3, "30+", $C['yellow']);
  141. imageString($im, $fn, $x+7+2*$r, $y+$r/3, "35+", $C['darkgreen']);
  142. imageString($im, $fn, $x+9+3*$r, $y+$r/3, "40+", $C['brightgreen']);
  143. }
  144. function radial($angle, $sz){
  145. #turn into radians
  146. $angle = deg2rad($angle);
  147. # determine length of radius
  148. $r = $sz * 0.5 * 0.95;
  149. # and convert length/azimuth to cartesian
  150. $x0 = sprintf("%d", (($sz * 0.5) - ($r * cos($angle))));
  151. $y0 = sprintf("%d", (($sz * 0.5) - ($r * sin($angle))));
  152. $x1 = sprintf("%d", (($sz * 0.5) + ($r * cos($angle))));
  153. $y1 = sprintf("%d", (($sz * 0.5) + ($r * sin($angle))));
  154. return array($x0, $y0, $x1, $y1);
  155. }
  156. function azel2xy($az, $el, $sz){
  157. #rotate coords... 90deg W = 180deg trig
  158. $az += 270;
  159. #turn into radians
  160. $az = deg2rad($az);
  161. # determine length of radius
  162. $r = $sz * 0.5 * 0.95;
  163. $r -= ($r * ($el/90));
  164. # and convert length/azimuth to cartesian
  165. $x = sprintf("%d", (($sz * 0.5) + ($r * cos($az))));
  166. $y = sprintf("%d", (($sz * 0.5) + ($r * sin($az))));
  167. $x = $sz - $x;
  168. return array($x, $y);
  169. }
  170. function cellplot($im, $sz, $C, $cellsize, $e){
  171. list($sv, $el, $az, $snr, $u) = $e;
  172. if ((0 == $sv) || (0 == $az + $el + $snr) ||
  173. ($az < 0) || ($el < 0))
  174. return;
  175. $color = $C['brightgreen'];
  176. if ($snr < 40)
  177. $color = $C['darkgreen'];
  178. if ($snr < 35)
  179. $color = $C['yellow'];
  180. if ($snr < 30)
  181. $color = $C['red'];
  182. if ($snr < 15)
  183. $color = $C['dkgray'];
  184. #consider an N-degree cell plotted at (0,0). its top left corner
  185. #will be (0,0) and its bottom right corner will be at (N,N). The
  186. #sides are straight lines from (0,0)-(0,N) and (N,0)-(N,N). The
  187. #top and bottom edges will be approximated by segments from
  188. #(0,0):(0,1)..(0,N-1):(0,N) and (N,0):(N,1)...(N,N-1):(N,N).
  189. #Plotting that unholy mess is the job of
  190. # imagefilledpolygon ( $image, array $points, $num_points, $color )
  191. $np = 0;
  192. $points = array();
  193. for($x = $az; $x <= $az+$cellsize; $x++){
  194. list($px,$py) = azel2xy($x, $el, $sz);
  195. array_push($points, $px, $py);
  196. $np++;
  197. }
  198. for($x = $az+$cellsize; $x >= $az; $x--){
  199. list($px,$py) = azel2xy($x, $el+$cellsize, $sz);
  200. array_push($points, $px, $py);
  201. $np++;
  202. }
  203. list($px,$py) = azel2xy($az, $el, $sz);
  204. array_push($points, $px, $py);
  205. $np++;
  206. if ($snr > 0)
  207. imageFilledPolygon($im, $points, $np, $color);
  208. }
  209. function splot($im, $sz, $C, $r, $filled, $e){
  210. list($sv, $az, $el, $snr, $u) = $e;
  211. if ((0 == $sv) || (0 == $az + $el + $snr))
  212. return;
  213. $color = $C['brightgreen'];
  214. if ($snr < 40)
  215. $color = $C['darkgreen'];
  216. if ($snr < 35)
  217. $color = $C['yellow'];
  218. if ($snr < 30)
  219. $color = $C['red'];
  220. if ($snr == 0)
  221. $color = $C['black'];
  222. list($x, $y) = azel2xy($el, $az, $sz);
  223. if ($snr > 0){
  224. if ($filled)
  225. imageFilledArc($im, $x, $y, $r, $r, 0, 360, $color, 0);
  226. else
  227. imageArc($im, $x, $y, $r, $r, 0, 360, $color);
  228. }
  229. }
  230. function elevation($im, $sz, $C, $a){
  231. $b = 90 - $a;
  232. $a = $sz * 0.95 * ($a/180);
  233. imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']);
  234. $x = $sz/2 - 16;
  235. $y = $sz/2 - $a;
  236. imageString($im, 2, $x, $y, $b, $C['ltgray']);
  237. }
  238. function skyview($im, $sz, $C){
  239. $a = 90; $a = $sz * 0.95 * ($a/180);
  240. imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['mdgray'], 0);
  241. imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['black']);
  242. $x = $sz/2 - 16; $y = $sz/2 - $a;
  243. imageString($im, 2, $x, $y, "0", $C['ltgray']);
  244. $a = 85; $a = $sz * 0.95 * ($a/180);
  245. imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['white'], 0);
  246. imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']);
  247. imageString($im, 1, $sz/2 - 6, $sz+$a, '5', $C['black']);
  248. $x = $sz/2 - 16; $y = $sz/2 - $a;
  249. imageString($im, 2, $x, $y, "5", $C['ltgray']);
  250. skygrid($im, $sz, $C);
  251. $x = $sz/2 - 16; $y = $sz/2 - 8;
  252. /* imageString($im, 2, $x, $y, "90", $C['ltgray']); */
  253. imageString($im, 4, $sz/2 + 4, 2 , 'N', $C['black']);
  254. imageString($im, 4, $sz/2 + 4, $sz - 16 , 'S', $C['black']);
  255. imageString($im, 4, 4 , $sz/2 + 4, 'E', $C['black']);
  256. imageString($im, 4, $sz - 10 , $sz/2 + 4, 'W', $C['black']);
  257. }
  258. function skygrid($im, $sz, $C){
  259. for($i = 0; $i < 180; $i += 15){
  260. list($x0, $y0, $x1, $y1) = radial($i, $sz);
  261. imageLine($im, $x0, $y0, $x1, $y1, $C['ltgray']);
  262. }
  263. for($i = 15; $i < 90; $i += 15)
  264. elevation($im, $sz, $C, $i);
  265. }
  266. ?>