[OpenWrt-Devel] [PATCH 2/2] [luci] add Huawei NCM protocol

Maarten Deprez deprez.maarten at gmail.com
Sat Mar 28 16:30:09 EDT 2015


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 <deprez.maarten at gmail.com>



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 <deprez.maarten at gmail.com>
+#
+# 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
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list