Adds Huawei NCM protocol as well as huawei modem status support for Luci. Based on the work of Oskari Rauta at https://sites.google.com/site/variousopenwrt/huawei-e3267 . This version adds frequency locking, between other things.
Signed-off-by: Maarten Deprez <[email protected]> diff --git a/protocols/luci-proto-huawei-ncm/Makefile b/protocols/luci-proto-huawei-ncm/Makefile new file mode 100644 index 0000000..720b590 --- /dev/null +++ b/protocols/luci-proto-huawei-ncm/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (C) 2014-2015 Maarten Deprez <[email protected]> +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Support for Huawei NCM +LUCI_DEPENDS:=+huawei-ncm + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/protocols/luci-proto-huawei-ncm/htdocs/luci-static/resources/huawei_ncm_xhr.js b/protocols/luci-proto-huawei-ncm/htdocs/luci-static/resources/huawei_ncm_xhr.js new file mode 100644 index 0000000..a3962c9 --- /dev/null +++ b/protocols/luci-proto-huawei-ncm/htdocs/luci-static/resources/huawei_ncm_xhr.js @@ -0,0 +1,247 @@ +/* + * xhr.js - XMLHttpRequest helper class + */ + +var gotinfoD = "0"; +var hwrefreshD = "0"; +var modemdevD = "" + +XHR2 = function() +{ + this.reinit = function() + { + if (window.XMLHttpRequest) { + this._xmlHttp = new XMLHttpRequest(); + } + else if (window.ActiveXObject) { + this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); + } + else { + alert("dongle_xhr.js: XMLHttpRequest is not supported by this browser!"); + } + } + + this.busy = function() { + if (!this._xmlHttp) + return false; + + switch (this._xmlHttp.readyState) + { + case 1: + case 2: + case 3: + return true; + + default: + return false; + } + } + + this.abort = function() { + if (this.busy()) + this._xmlHttp.abort(); + } + + this.get = function(url,data,callback) + { + this.reinit(); + + var xhr2 = this._xmlHttp; + var code = this._encode(data); + + url = location.protocol + '//' + location.host + url; + + if (code) + if (url.substr(url.length-1,1) == '&') + url += code; + else + url += '?' + code; + + xhr2.open('GET', url, true); + + xhr2.onreadystatechange = function() + { + if (xhr2.readyState == 4) { + var json = null; + if (xhr2.getResponseHeader("Content-Type") == "application/json") { + try { + json = eval('(' + xhr2.responseText + ')'); + } + catch(e) { + json = null; + } + } + + callback(xhr2, json); + } + } + + xhr2.send(null); + } + + this.post = function(url,data,callback) + { + this.reinit(); + + var xhr2 = this._xmlHttp; + var code = this._encode(data); + + xhr2.onreadystatechange = function() + { + if (xhr2.readyState == 4) + callback(xhr2); + } + + xhr2.open('POST', url, true); + xhr2.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhr2.setRequestHeader('Content-length', code.length); + xhr2.setRequestHeader('Connection', 'close'); + xhr2.send(code); + } + + this.cancel = function() + { + this._xmlHttp.onreadystatechange = function(){}; + this._xmlHttp.abort(); + } + + this.send_form = function(form,callback,extra_values) + { + var code = ''; + + for (var i = 0; i < form.elements.length; i++) + { + var e = form.elements[i]; + + if (e.options) + { + code += (code ? '&' : '') + + form.elements[i].name + '=' + encodeURIComponent( + e.options[e.selectedIndex].value + ); + } + else if (e.length) + { + for (var j = 0; j < e.length; j++) + if (e[j].name) { + code += (code ? '&' : '') + + e[j].name + '=' + encodeURIComponent(e[j].value); + } + } + else + { + code += (code ? '&' : '') + + e.name + '=' + encodeURIComponent(e.value); + } + } + + if (typeof extra_values == 'object') + for (var key in extra_values) + code += (code ? '&' : '') + + key + '=' + encodeURIComponent(extra_values[key]); + + return( + (form.method == 'get') + ? this.get(form.getAttribute('action'), code, callback) + : this.post(form.getAttribute('action'), code, callback) + ); + } + + this._encode = function(obj) + { + obj = obj ? obj : { }; + obj['gotinfo'] = gotinfoD; + obj['hwrefresh'] = hwrefreshD; + obj['modemdev'] = modemdevD; + obj['_'] = Math.random(); + + if (typeof obj == 'object') + { + + var code = ''; + + for (var k in obj) + code += (code ? '&' : '') + + k + '=' + encodeURIComponent(obj[k]); + + return code; + } + + return obj; + } +} + +XHR2.get = function(url, data, callback) +{ + (new XHR2()).get(url, data, callback); +} + +XHR2.poll = function(interval, url, data, callback) +{ + if (isNaN(interval) || interval < 1) + interval = 5; + + if (!XHR2._q) + { + XHR2._t = 0; + XHR2._q = [ ]; + XHR2._r = function() { + for (var i = 0, e = XHR2._q[0]; i < XHR2._q.length; e = XHR2._q[++i]) + { + if (!(XHR2._t % e.interval) && !e.xhr2.busy()) + e.xhr2.get(e.url, e.data, e.callback); + } + + XHR2._t++; + }; + } + + XHR2._q.push({ + interval: interval, + callback: callback, + url: url, + data: data, + xhr2: new XHR2() + }); + + XHR2.run(); +} + +XHR2.halt = function() +{ + if (XHR2._i) + { + /* show & set poll indicator */ + try { + document.getElementById('xhr_poll_status').style.display = ''; + document.getElementById('xhr_poll_status_on').style.display = 'none'; + document.getElementById('xhr_poll_status_off').style.display = ''; + } catch(e) { } + + window.clearInterval(XHR2._i); + XHR2._i = null; + } +} + +XHR2.run = function() +{ + if (XHR2._r && !XHR2._i) + { + /* show & set poll indicator */ + try { + document.getElementById('xhr_poll_status').style.display = ''; + document.getElementById('xhr_poll_status_on').style.display = ''; + document.getElementById('xhr_poll_status_off').style.display = 'none'; + } catch(e) { } + + /* kick first round manually to prevent one second lag when setting up + * the poll interval */ + XHR2._r(); + XHR2._i = window.setInterval(XHR2._r, 1000); + } +} + +XHR2.running = function() +{ + return !!(XHR2._r && XHR2._i); +} diff --git a/protocols/luci-proto-huawei-ncm/luasrc/controller/huawei_ncm.lua b/protocols/luci-proto-huawei-ncm/luasrc/controller/huawei_ncm.lua new file mode 100644 index 0000000..dc63872 --- /dev/null +++ b/protocols/luci-proto-huawei-ncm/luasrc/controller/huawei_ncm.lua @@ -0,0 +1,8 @@ +module("luci.controller.huawei_ncm", package.seeall) + +function index() + local page + + page = entry({"admin", "status", "huawei_ncm"}, template("huawei_ncm/status"), _("Huawei NCM")) + page.dependent = true +end diff --git a/protocols/luci-proto-huawei-ncm/luasrc/model/cbi/admin_network/proto_huawei_ncm.lua b/protocols/luci-proto-huawei-ncm/luasrc/model/cbi/admin_network/proto_huawei_ncm.lua new file mode 100644 index 0000000..b466f23 --- /dev/null +++ b/protocols/luci-proto-huawei-ncm/luasrc/model/cbi/admin_network/proto_huawei_ncm.lua @@ -0,0 +1,91 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local map, section, net = ... +local ifc = net:get_interface() + +local apn, mode, freq, pin, timeout, interval +local bcast, defaultroute, peerdns, dns, metric + + +mode = section:taboption("general", ListValue, "mode", + translate("Service mode"), + translate("Allows to alter preferences for or restrict to certain types of network")) +mode:value("gsm", translate("GSM only")) +mode:value("wcdma", translate("WCDMA only")) +mode:value("gsmfirst", translate("GSM, WCDMA")) +mode:value("wcdmafirst", translate("WCDMA, GSM")) +mode:value("auto", translate("Automatic")) +mode.default = "auto" + + +apn = section:taboption("general", Value, "apn", translate("APN")) + +pin = section:taboption("general", Value, "pin", translate("PIN")) + +timeout = section:taboption("advanced", Value, "timeout", + translate("Registration and connection timeout"), + translate("Time (in seconds) to wait for network registration and data connection establishment")) +timeout.placeholder = 15 + +interval = section:taboption("advanced", Value, "interval", + translate("Connection check interval"), + translate("Time (in seconds) between connection checks")) +interval.placeholder = 60 + +freq = section:taboption("advanced", Value, "freq", + translate("Frequency lock"), + translate("If set to a value other than none, lock to a given frequency (i.e. cell tower)")) + +freq:value("0", translate("None")) +freq.default = "0" + +local pipe = io.popen("/usr/bin/huawei-ncm-cells") +local line = pipe:read("*line") +while line do + freq:value(line:match("%d+"), line) + line = pipe:read("*line") +end + +bcast = section:taboption("advanced", Flag, "broadcast", + translate("Use broadcast flag"), + translate("Required for certain ISPs, e.g. Charter with DOCSIS 3")) + +bcast.default = bcast.disabled + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" + +luci.tools.proto.opt_macaddr(section, ifc, translate("Override MAC address")) + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1492" +mtu.datatype = "max(9200)" diff --git a/protocols/luci-proto-huawei-ncm/luasrc/model/network/proto_huawei_ncm.lua b/protocols/luci-proto-huawei-ncm/luasrc/model/network/proto_huawei_ncm.lua new file mode 100644 index 0000000..e9f568b --- /dev/null +++ b/protocols/luci-proto-huawei-ncm/luasrc/model/network/proto_huawei_ncm.lua @@ -0,0 +1,13 @@ +local proto = luci.model.network:register_protocol("huawei_ncm") + +function proto.get_i18n(self) + return luci.i18n.translate("Huawei NCM") +end + +function proto.is_installed(self) + return nixio.fs.access("/lib/netifd/proto/huawei_ncm.sh") +end + +function proto.opkg_package(self) + return "huawei_ncm" +end diff --git a/protocols/luci-proto-huawei-ncm/luasrc/view/huawei_ncm/status.htm b/protocols/luci-proto-huawei-ncm/luasrc/view/huawei_ncm/status.htm new file mode 100644 index 0000000..1edd7df --- /dev/null +++ b/protocols/luci-proto-huawei-ncm/luasrc/view/huawei_ncm/status.htm @@ -0,0 +1,172 @@ +<%# +LuCI - Lua Configuration Interface +-%> + +<% + require "luci.sys" + require "luci.fs" + + local rv = { + gotinfo = "0", + interface = "", + vendor = "", + model = "", + notification = "", + firmware = "", + imei = "", + provider = "", + mode = "", + downlink = "", + uplink = "", + freqlock = "", + lac = "", + ci = "", + freq = "", + network = "", + signal = "", + rssi = "", + rcsp = "", + ecio = "" + } + + if ( luci.http.formvalue("status") == "1" ) then + + local modeminfo = luci.sys.exec("/usr/bin/huawei-ncm-info", "") + + for k, v in string.gmatch(modeminfo, "(%w+) ([^\n]+)\n") do + rv[k] = v + end + + rv["gotinfo"] = "1" + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + + return + + end + +-%> + +<%+header%> + +<script type="text/javascript" src="<%=resource%>/cbi.js"></script> +<script type="text/javascript" src="<%=resource%>/huawei_ncm_xhr.js"></script> +<script type="text/javascript">//<![CDATA[ + + function capitalize(s) + { + return s.toLowerCase().replace( /\b./g, function(a){ return a.toUpperCase(); } ); + }; + + XHR2.poll(5, '<%=REQUEST_URI%>', { status: 1 }, + function(x, info) + { + + var e; + + if (e = document.getElementById('notification')) + e.innerHTML = info.notification; + + if (info.gotinfo == "1") { + + if (e = document.getElementById('name')) + e.innerHTML = capitalize(info.vendor) + " " + capitalize(info.model); + + if (e = document.getElementById('firmware')) + e.innerHTML = info.firmware; + + if (e = document.getElementById('imei')) + e.innerHTML = info.imei; + + if (e = document.getElementById('provider')) + e.innerHTML = info.provider; + + if (e = document.getElementById('linkspeed')) + if ( info.downlink != "" && info.uplink != "" ) + e.innerHTML = info.downlink + " / " + info.uplink ; + + if (e = document.getElementById('freqlock')) + e.innerHTML = info.freqlock; + + if (e = document.getElementById('mode')) + e.innerHTML = info.mode; + + if (e = document.getElementById('ci')) + e.innerHTML = info.ci; + + if (e = document.getElementById('lac')) + e.innerHTML = info.lac; + + if (e = document.getElementById('freq')) + e.innerHTML = info.freq; + + if (e = document.getElementById('network')) + e.innerHTML = info.network; + + if (e = document.getElementById('signal')) + e.innerHTML = info.signal; + + if (e = document.getElementById('rssi')) + e.innerHTML = info.rssi; + + if (e = document.getElementById('rcsp')) + e.innerHTML = info.rcsp; + + if (e = document.getElementById('ecio')) + e.innerHTML = info.ecio; + + } + + modemdevD = info.modemdev; + gotinfoD = info.gotinfo; + } + ); + +//]]></script> + +<h2><a id="content" name="content"><%:Huawei NCM Status%></a></h2> +<small style="color: #777;" id="notification"></small> + +<fieldset class="cbi-section"> + <legend id="name"><%:Detecting dongle%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Firmware version%></td><td id="firmware"></td></tr> + <tr><td width="33%"><%:IMEI%></td><td id="imei"></td></tr> + </table> +</fieldset> + +<fieldset class="cbi-section"> +<legend><%:Network%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Provider%></td><td id="provider"></td></tr> + <tr><td width="33%"><%:Downlink/Uplink%></td><td id="linkspeed"></td></tr> + <tr><td width="33%"><%:Mode%></td><td id="mode"></td></tr> + <tr><td width="33%"><%:Freq lock%></td><td id="freqlock"></td></tr> + </table> +</fieldset> + +<fieldset class="cbi-section"> + <legend><%:Cell%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Location Area Code%></td><td id="lac"></td></tr> + <tr><td width="33%"><%:Cell ID%></td><td id="ci"></td></tr> + <tr><td width="33%"><%:Cell Freq%></td><td id="freq"></td></tr> + </table> +</fieldset> + +<fieldset class="cbi-section"> + <legend><%:Signal level%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Network%></td><td id="network"></td></tr> + <tr><td width="33%"><%:Signal strength%></td><td id="signal"></td></tr> + <tr><td width="33%"><%:RSSI%></td><td id="rssi"></td></tr> + <tr><td width="33%"><%:RCSP%></td><td id="rcsp"></td></tr> + <tr><td width="33%"><%:ECIO%></td><td id="ecio"></td></tr> + </table> +</fieldset> +<%+footer%> _______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
