UI cleanup, phase 5, MIPS (mostly cosmetic)
[tomato.git] / release / src / router / www / tools-survey.asp
blob8e59ebdecc4c0d20c5c09247c6369e88c83da3c3
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 <meta name="viewport" content="width=device-width">
15 <title>[<% ident(); %>] Tools: Wireless Survey</title>
16 <link rel='stylesheet' type='text/css' href='tomato.css'>
17 <link rel='stylesheet' type='text/css' href='color.css'>
18 <script type='text/javascript' src='tomato.js'></script>
20 <!-- / / / -->
21 <style type='text/css'>
22 #survey-grid .brate {
23 color: blue;
25 #survey-grid .grate {
26 color: green;
28 #survey-grid .co4,
29 #survey-grid .co5 {
30 text-align: right;
32 #survey-grid .co6,
33 #survey-grid .co7 {
34 text-align: center;
36 #survey-msg {
37 border: 1px dashed #f0f0f0;
38 background: #fefefe;
39 padding: 5px;
40 width: 300px;
41 position: absolute;
43 #survey-controls {
44 text-align: right;
46 #expire-time {
47 width: 120px;
49 </style>
51 <script type='text/javascript' src='debug.js'></script>
53 <script type='text/javascript'>
54 // <% nvram(''); %> // http_id
56 var wlscandata = [];
57 var entries = [];
58 var dayOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
60 Date.prototype.toWHMS = function() {
61 return dayOfWeek[this.getDay()] + ' ' + this.getHours() + ':' + this.getMinutes().pad(2)+ ':' + this.getSeconds().pad(2);
64 var sg = new TomatoGrid();
66 sg.sortCompare = function(a, b) {
67 var col = this.sortColumn;
68 var da = a.getRowData();
69 var db = b.getRowData();
70 var r;
72 switch (col) {
73 case 0:
74 r = -cmpDate(da.lastSeen, db.lastSeen);
75 break;
76 case 3:
77 r = cmpInt(da.rssi, db.rssi);
78 break;
79 case 4:
80 r = cmpInt(da.noise, db.noise);
81 break;
82 case 5:
83 r = cmpInt(da.qual, db.qual);
84 break;
85 case 6:
86 r = cmpInt(da.channel, db.channel);
87 break;
88 default:
89 r = cmpText(a.cells[col].innerHTML, b.cells[col].innerHTML);
91 if (r == 0) r = cmpText(da.bssid, db.bssid);
93 return this.sortAscending ? r : -r;
96 sg.rateSorter = function(a, b)
98 if (a < b) return -1;
99 if (a > b) return 1;
100 return 0;
103 sg.populate = function()
105 var caps = ['infra', 'adhoc', 'poll', 'pollreq', 'wep', 'shortpre', 'pbcc', 'agility', 'X', 'Y', 'shortslot'];
106 var ncap = '802.11n';
107 var added = 0;
108 var removed = 0;
109 var i, j, k, t, e, s;
111 if ((wlscandata.length == 1) && (!wlscandata[0][0])) {
112 setMsg("error: " + wlscandata[0][1]);
113 return;
116 for (i = 0; i < wlscandata.length; ++i) {
117 s = wlscandata[i];
118 e = null;
120 for (j = 0; j < entries.length; ++j) {
121 if (entries[j].bssid == s[0]) {
122 e = entries[j];
123 break;
126 if (!e) {
127 ++added;
128 e = {};
129 e.firstSeen = new Date();
130 entries.push(e);
132 e.lastSeen = new Date();
133 e.bssid = s[0];
134 e.ssid = s[1];
135 e.channel = s[2];
136 e.rssi = s[4];
137 e.noise = s[5];
138 e.saw = 1;
140 t = '';
141 k = 0;
142 for (j = 0; j < caps.length; ++j) {
143 if ((s[3] & (1 << j)) && (caps[j])) {
144 k += caps[j].length;
145 if (k > 12) {
146 t += '<br>';
147 k = caps[j].length;
149 else t += ' ';
150 t += caps[j];
153 if (s[7] != 0) {
154 k += ncap.length;
155 t += ((k > 12) ? '<br>' : ' ') + ncap;
157 e.cap = t;
159 t = '';
160 var rb = [];
161 var rg = [];
162 for (j = 0; j < s[6].length; ++j) {
163 var x = s[6][j];
164 var r = (x & 0x7F) / 2;
165 if (x & 0x80) rb.push(r);
166 else rg.push(r);
168 rb.sort(this.rateSorter);
169 rg.sort(this.rateSorter);
171 t = '';
172 if (rb.length) t = '<span class="brate">' + rb.join(',') + '</span>';
173 if (rg.length) {
174 if (rb.length) t += '<br>';
175 t +='<span class="grate">' + rg.join(',') + '</span>';
177 e.rates = t;
180 t = E('expire-time').value;
181 if (t > 0) {
182 var cut = (new Date()).getTime() - (t * 1000);
183 for (i = 0; i < entries.length; ) {
184 if (entries[i].lastSeen.getTime() < cut) {
185 entries.splice(i, 1);
186 ++removed;
188 else ++i;
192 for (i = 0; i < entries.length; ++i) {
193 var seen, m, mac;
195 e = entries[i];
197 if (!e.saw) {
198 e.rssi = MAX(e.rssi - 5, -101);
199 e.noise = MAX(e.noise - 2, -101);
200 if ((e.rssi == -101) || (e.noise == -101))
201 e.noise = e.rssi = -999;
203 e.saw = 0;
205 e.qual = MAX(e.rssi - e.noise, 0);
207 seen = e.lastSeen.toWHMS();
208 if (useAjax()) {
209 m = Math.floor(((new Date()).getTime() - e.firstSeen.getTime()) / 60000);
210 if (m <= 10) seen += '<br> <b><small>NEW (' + -m + 'm)</small></b>';
213 mac = e.bssid;
214 if (mac.match(/^(..):(..):(..)/))
215 mac = '<a href="http://api.macvendors.com/' + RegExp.$1 + '-' + RegExp.$2 + '-' + RegExp.$3 + '" target="_new" title="OUI Search">' + mac + '</a>';
217 sg.insert(-1, e, [
218 '<small>' + seen + '</small>',
219 '' + e.ssid,
220 mac,
221 (e.rssi == -999) ? '' : (e.rssi + ' <small>dBm</small>'),
222 (e.noise == -999) ? '' : (e.noise + ' <small>dBm</small>'),
223 '<small>' + e.qual + '</small> <img src="bar' + MIN(MAX(Math.floor(e.qual / 10), 1), 6) + '.gif">',
224 '' + e.channel,
225 '' + e.cap,
226 '' + e.rates], false);
229 s = '';
230 if (useAjax()) s = added + ' added, ' + removed + ' removed, ';
231 s += entries.length + ' total.';
233 s += '<br><br><small>Last updated: ' + (new Date()).toWHMS() + '</small>';
234 setMsg(s);
236 wlscandata = [];
239 sg.setup = function() {
240 this.init('survey-grid', 'sort');
241 this.headerSet(['Last Seen', 'SSID', 'BSSID', 'RSSI &nbsp; &nbsp; ', 'Noise &nbsp; &nbsp; ', 'Quality', 'Ch', 'Capabilities', 'Rates']);
242 this.populate();
243 this.sort(0);
247 function setMsg(msg)
249 E('survey-msg').innerHTML = msg;
253 var ref = new TomatoRefresh('update.cgi', 'exec=wlscan', 0, 'tools_survey_refresh');
255 ref.refresh = function(text)
257 try {
258 eval(text);
260 catch (ex) {
261 return;
263 sg.removeAllData();
264 sg.populate();
265 sg.resort();
268 function earlyInit()
270 if (!useAjax()) E('expire-time').style.visibility = 'hidden';
271 sg.setup();
274 function init()
276 sg.recolor();
277 ref.initPage();
279 </script>
280 </head>
281 <body onload='init()'>
282 <form action='javascript:{}'>
283 <table id='container' cellspacing=0>
284 <tr><td colspan=2 id='header'>
285 <div class='title'>Tomato</div>
286 <div class='version'>Version <% version(); %></div>
287 </td></tr>
288 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
289 <td id='content'>
290 <div id='ident'><% ident(); %></div>
292 <!-- / / / -->
294 <div class='section-title'>Wireless Site Survey</div>
295 <div class='section'>
296 <table id='survey-grid' class='tomato-grid' cellspacing=0></table>
297 <div id='survey-msg'></div>
298 <div id='survey-controls'>
299 <img src="spin.gif" id="refresh-spinner">
300 <script type='text/javascript'>
301 genStdTimeList('expire-time', 'Auto Expire', 0);
302 genStdTimeList('refresh-time', 'Auto Refresh', 0);
303 </script>
304 <input type="button" value="Refresh" onclick="ref.toggle()" id="refresh-button">
305 </div>
307 <br><br><br><br>
308 <script type='text/javascript'>
309 if ('<% wlclient(); %>' == '0') {
310 document.write('<small>Warning: Wireless connections to this router may be disrupted while using this tool.</small>');
312 </script>
313 </div>
315 <!-- / / / -->
317 </td></tr>
318 <tr><td id='footer' colspan=2>&nbsp;</td></tr>
319 </table>
320 </form>
321 <script type='text/javascript'>earlyInit();</script>
322 </body>
323 </html>