Tomato 1.28
[tomato/tomato-null.git] / release / src / router / www / tools-survey.asp
blob54f4a92632d4eee74bd742bc23483f2052c13927
1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN'>
2 <!--
3 Tomato GUI
4 Copyright (C) 2006-2010 Jonathan Zarate
5 http://www.polarcloud.com/tomato/
7 For use with Tomato Firmware only.
8 No part of this file may be used without permission.
9 -->
10 <html>
11 <head>
12 <meta http-equiv='content-type' content='text/html;charset=utf-8'>
13 <meta name='robots' content='noindex,nofollow'>
14 <title>[<% ident(); %>] Tools: Wireless Survey</title>
15 <link rel='stylesheet' type='text/css' href='tomato.css'>
16 <link rel='stylesheet' type='text/css' href='color.css'>
17 <script type='text/javascript' src='tomato.js'></script>
19 <!-- / / / -->
20 <style type='text/css'>
21 #survey-grid .brate {
22 color: blue;
24 #survey-grid .grate {
25 color: green;
27 #survey-grid .co4,
28 #survey-grid .co5 {
29 text-align: right;
31 #survey-grid .co6,
32 #survey-grid .co7 {
33 text-align: center;
35 #survey-msg {
36 border: 1px dashed #f0f0f0;
37 background: #fefefe;
38 padding: 5px;
39 width: 300px;
40 position: absolute;
42 #survey-controls {
43 text-align: right;
45 #expire-time {
46 width: 120px;
48 </style>
50 <script type='text/javascript' src='debug.js'></script>
52 <script type='text/javascript'>
53 // <% nvram(''); %> // http_id
55 var wlscandata = [];
56 var entries = [];
57 var dayOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
59 Date.prototype.toWHMS = function() {
60 return dayOfWeek[this.getDay()] + ' ' + this.getHours() + ':' + this.getMinutes().pad(2)+ ':' + this.getSeconds().pad(2);
63 var sg = new TomatoGrid();
65 sg.sortCompare = function(a, b) {
66 var col = this.sortColumn;
67 var da = a.getRowData();
68 var db = b.getRowData();
69 var r;
71 switch (col) {
72 case 0:
73 r = -cmpDate(da.lastSeen, db.lastSeen);
74 break;
75 case 3:
76 r = cmpInt(da.rssi, db.rssi);
77 break;
78 case 4:
79 r = cmpInt(da.noise, db.noise);
80 break;
81 case 5:
82 r = cmpInt(da.qual, db.qual);
83 break;
84 case 6:
85 r = cmpInt(da.channel, db.channel);
86 break;
87 default:
88 r = cmpText(a.cells[col].innerHTML, b.cells[col].innerHTML);
90 if (r == 0) r = cmpText(da.bssid, db.bssid);
92 return this.sortAscending ? r : -r;
95 sg.rateSorter = function(a, b)
97 if (a < b) return -1;
98 if (a > b) return 1;
99 return 0;
102 sg.populate = function()
104 var caps = ['infra', 'adhoc', 'poll', 'pollreq', 'wep', 'shortpre', 'pbcc', 'agility', 'X', 'Y', 'shortslot'];
105 var added = 0;
106 var removed = 0;
107 var i, j, k, t, e, s;
109 if ((wlscandata.length == 1) && (!wlscandata[0][0])) {
110 setMsg("error: " + wlscandata[0][1]);
111 return;
114 for (i = 0; i < wlscandata.length; ++i) {
115 s = wlscandata[i];
116 e = null;
118 for (j = 0; j < entries.length; ++j) {
119 if (entries[j].bssid == s[0]) {
120 e = entries[j];
121 break;
124 if (!e) {
125 ++added;
126 e = {};
127 e.firstSeen = new Date();
128 entries.push(e);
130 e.lastSeen = new Date();
131 e.bssid = s[0];
132 e.ssid = s[1];
133 e.channel = s[2];
134 e.rssi = s[4];
135 e.noise = s[5];
136 e.saw = 1;
138 t = '';
139 k = 0;
140 for (j = 0; j < caps.length; ++j) {
141 if ((s[3] & (1 << j)) && (caps[j])) {
142 k += caps[j].length;
143 if (k > 12) {
144 t += '<br>';
145 k = caps[j].length;
147 else t += ' ';
148 t += caps[j];
151 e.cap = t;
153 t = '';
154 var rb = [];
155 var rg = [];
156 for (j = 0; j < s[6].length; ++j) {
157 var x = s[6][j];
158 var r = (x & 0x7F) / 2;
159 if (x & 0x80) rb.push(r);
160 else rg.push(r);
162 rb.sort(this.rateSorter);
163 rg.sort(this.rateSorter);
165 t = '';
166 if (rb.length) t = '<span class="brate">' + rb.join(',') + '</span>';
167 if (rg.length) {
168 if (rb.length) t += '<br>';
169 t +='<span class="grate">' + rg.join(',') + '</span>';
171 e.rates = t;
174 t = E('expire-time').value;
175 if (t > 0) {
176 var cut = (new Date()).getTime() - (t * 1000);
177 for (i = 0; i < entries.length; ) {
178 if (entries[i].lastSeen.getTime() < cut) {
179 entries.splice(i, 1);
180 ++removed;
182 else ++i;
186 for (i = 0; i < entries.length; ++i) {
187 var seen, m, mac;
189 e = entries[i];
191 if (!e.saw) {
192 e.rssi = MAX(e.rssi - 5, -101);
193 e.noise = MAX(e.noise - 2, -101);
194 if ((e.rssi == -101) || (e.noise == -101))
195 e.noise = e.rssi = -999;
197 e.saw = 0;
199 e.qual = MAX(e.rssi - e.noise, 0);
201 seen = e.lastSeen.toWHMS();
202 if (useAjax()) {
203 m = Math.floor(((new Date()).getTime() - e.firstSeen.getTime()) / 60000);
204 if (m <= 10) seen += '<br> <b><small>NEW (' + -m + 'm)</small></b>';
207 mac = e.bssid;
208 if (mac.match(/^(..):(..):(..)/))
209 mac = '<a href="http://standards.ieee.org/cgi-bin/ouisearch?' + RegExp.$1 + '-' + RegExp.$2 + '-' + RegExp.$3 + '" target="_new" title="OUI search">' + mac + '</a>';
211 sg.insert(-1, e, [
212 '<small>' + seen + '</small>',
213 '' + e.ssid,
214 mac,
215 (e.rssi == -999) ? '' : (e.rssi + ' <small>dBm</small>'),
216 (e.noise == -999) ? '' : (e.noise + ' <small>dBm</small>'),
217 '<small>' + e.qual + '</small> <img src="bar' + MIN(MAX(Math.floor(e.qual / 10), 1), 6) + '.gif">',
218 '' + e.channel,
219 '' + e.cap,
220 '' + e.rates], false);
223 s = '';
224 if (useAjax()) s = added + ' added, ' + removed + ' removed, ';
225 s += entries.length + ' total.';
227 s += '<br><br><small>Last updated: ' + (new Date()).toWHMS() + '</small>';
228 setMsg(s);
230 wlscandata = [];
233 sg.setup = function() {
234 this.init('survey-grid', 'sort');
235 this.headerSet(['Last Seen', 'SSID', 'BSSID', 'RSSI &nbsp; &nbsp; ', 'Noise &nbsp; &nbsp; ', 'Quality', 'Ch', 'Capabilities', 'Rates']);
236 this.populate();
237 this.sort(0);
241 function setMsg(msg)
243 E('survey-msg').innerHTML = msg;
247 var ref = new TomatoRefresh('update.cgi', 'exec=wlscan', 0, 'tools_survey_refresh');
249 ref.refresh = function(text)
251 try {
252 eval(text);
254 catch (ex) {
255 return;
257 sg.removeAllData();
258 sg.populate();
259 sg.resort();
262 function earlyInit()
264 if (!useAjax()) E('expire-time').style.visibility = 'hidden';
265 sg.setup();
268 function init()
270 sg.recolor();
271 ref.initPage();
273 </script>
274 </head>
275 <body onload='init()'>
276 <form action='javascript:{}'>
277 <table id='container' cellspacing=0>
278 <tr><td colspan=2 id='header'>
279 <div class='title'>Tomato</div>
280 <div class='version'>Version <% version(); %></div>
281 </td></tr>
282 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
283 <td id='content'>
284 <div id='ident'><% ident(); %></div>
286 <!-- / / / -->
288 <div class='section-title'>Wireless Site Survey</div>
289 <div class='section'>
290 <table id='survey-grid' class='tomato-grid' cellspacing=0></table>
291 <div id='survey-msg'></div>
292 <div id='survey-controls'>
293 <img src="spin.gif" id="refresh-spinner">
294 <script type='text/javascript'>
295 genStdTimeList('expire-time', 'Auto Expire', 0);
296 genStdTimeList('refresh-time', 'Auto Refresh', 0);
297 </script>
298 <input type="button" value="Refresh" onclick="ref.toggle()" id="refresh-button">
299 </div>
301 <br><br><br><br>
302 <script type='text/javascript'>
303 if ('<% wlclient(); %>' == '0') {
304 document.write('<small>Warning: Wireless connections to this router may be disrupted while using this tool.</small>');
306 </script>
307 </div>
309 <!-- / / / -->
311 </td></tr>
312 <tr><td id='footer' colspan=2>&nbsp;</td></tr>
313 </table>
314 </form>
315 <script type='text/javascript'>earlyInit();</script>
316 </body>
317 </html>