From 6fc1db3a709e2bfd06ab806d4acfad373a641f87 Mon Sep 17 00:00:00 2001
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Mon, 4 May 2015 04:34:23 +0200
Subject: [PATCH] gluon-luci-wifi-config: add txpower setting

Fixes #219
---
 package/gluon-luci-wifi-config/Makefile       |   2 +-
 .../lua/luci/model/cbi/admin/wifi-config.lua  | 108 +++++++++++++++---
 package/gluon-luci-wifi-config/i18n/de.po     |  22 +++-
 .../i18n/gluon-luci-wifi-config.pot           |  11 +-
 4 files changed, 122 insertions(+), 21 deletions(-)

diff --git a/package/gluon-luci-wifi-config/Makefile b/package/gluon-luci-wifi-config/Makefile
index 75e708637..462eab9f4 100644
--- a/package/gluon-luci-wifi-config/Makefile
+++ b/package/gluon-luci-wifi-config/Makefile
@@ -13,7 +13,7 @@ PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
 define Package/gluon-luci-wifi-config
   SECTION:=gluon
   CATEGORY:=Gluon
-  DEPENDS:=+gluon-luci-admin
+  DEPENDS:=+gluon-luci-admin +libiwinfo-lua
   TITLE:=UI for Wifi Settings
 endef
 
diff --git a/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua b/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua
index 1b8ef7c46..720346d3d 100644
--- a/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua
+++ b/package/gluon-luci-wifi-config/files/usr/lib/lua/luci/model/cbi/admin/wifi-config.lua
@@ -1,13 +1,54 @@
-local f, s, o
 local uci = luci.model.uci.cursor()
+local fs = require 'nixio.fs'
 
-f = SimpleForm("wifi", translate("WLAN"))
+
+local function find_phy_by_path(path)
+  for phy in fs.glob("/sys/devices/" .. path .. "/ieee80211/phy*") do
+    return phy:match("([^/]+)$")
+  end
+end
+
+local function find_phy_by_macaddr(macaddr)
+  local addr = macaddr:lower()
+  for file in fs.glob("/sys/class/ieee80211/*/macaddress") do
+    if luci.util.trim(fs.readfile(file)) == addr then
+      return file:match("([^/]+)/macaddress$")
+    end
+  end
+end
+
+local function txpower_list(iw)
+  local list = iw.txpwrlist or { }
+  local off  = tonumber(iw.txpower_offset) or 0
+  local new  = { }
+  local prev = -1
+  local _, val
+  for _, val in ipairs(list) do
+    local dbm = val.dbm + off
+    local mw  = math.floor(10 ^ (dbm / 10))
+    if mw ~= prev then
+      prev = mw
+      table.insert(new, {
+                     display_dbm = dbm,
+                     display_mw  = mw,
+                     driver_dbm  = val.dbm,
+      })
+    end
+  end
+  return new
+end
+
+
+local f = SimpleForm("wifi", translate("WLAN"))
 f.template = "admin/expertmode"
 
-s = f:section(SimpleSection, nil, translate(
+local s = f:section(SimpleSection, nil, translate(
                 "You can enable or disable your node's client and mesh network "
                   .. "SSIDs here. Please don't disable the mesh network without "
-                  .. "a good reason, so other nodes can mesh with yours."
+                  .. "a good reason, so other nodes can mesh with yours.<br /><br />"
+                  .. "It is also possible to configure the WLAN adapters transmission power "
+                  .. "here. Please note that the transmission power values include the antenna gain "
+                  .. "where available, but there are many devices for which the gain is unavailable or inaccurate."
 ))
 
 local radios = {}
@@ -21,24 +62,56 @@ uci:foreach('wireless', 'wifi-device',
 
 -- add a client and mesh checkbox for each interface
 for _, radio in ipairs(radios) do
-  local hwmode = uci:get('wireless', radio, 'hwmode')
+  local config = uci:get_all('wireless', radio)
   local p
 
-  if hwmode == '11g' or hwmode == '11ng' then
+  if config.hwmode == '11g' or config.hwmode == '11ng' then
     p = f:section(SimpleSection, translate("2.4GHz WLAN"))
-  elseif hwmode == '11a' or hwmode == '11na' then
+  elseif config.hwmode == '11a' or config.hwmode == '11na' then
     p = f:section(SimpleSection, translate("5GHz WLAN"))
   end
 
   if p then
+    local o
+
     --box for the client network
-    o = p:option(Flag, 'clientbox_' .. radio, translate("Enable client network"))
+    o = p:option(Flag, radio .. '_client_enabled', translate("Enable client network"))
     o.default = uci:get_bool('wireless', 'client_' .. radio, "disabled") and o.disabled or o.enabled
     o.rmempty = false
+
     --box for the mesh network
-    o = p:option(Flag, 'meshbox_' .. radio, translate("Enable mesh network"))
+    o = p:option(Flag, radio .. '_mesh_enabled', translate("Enable mesh network"))
     o.default = uci:get_bool('wireless', 'mesh_' .. radio, "disabled") and o.disabled or o.enabled
     o.rmempty = false
+
+    local phy
+
+    if config.path then
+      phy = find_phy_by_path(config.path)
+    elseif config.macaddr then
+      phy = find_phy_by_path(config.macaddr)
+    end
+
+    if phy then
+      local iw = luci.sys.wifi.getiwinfo(phy)
+      if iw then
+        local txpowers = txpower_list(iw)
+
+        if #txpowers > 1 then
+          local tp = p:option(ListValue, radio .. '_txpower', translate("Transmission power"))
+          tp.rmempty = true
+          tp.default = uci:get('wireless', radio, 'txpower') or 'default'
+
+          tp:value('default', translate("(default)"))
+
+          table.sort(txpowers, function(a, b) return a.driver_dbm > b.driver_dbm end)
+
+          for _, entry in ipairs(txpowers) do
+            tp:value(entry.driver_dbm, "%i dBm (%i mW)" % {entry.display_dbm, entry.display_mw})
+          end
+        end
+      end
+    end
   end
 
 end
@@ -50,20 +123,25 @@ function f.handle(self, state, data)
     for _, radio in ipairs(radios) do
 
       local clientdisabled = 0
-      local meshdisabled = 0
-      -- get and invert the data from the boxes
-      if data["clientbox_"..radio] == '0' then
+      if data[radio .. '_client_enabled'] == '0' then
         clientdisabled = 1
       end
-      -- write the data to the config file
       uci:set('wireless', 'client_' .. radio, "disabled", clientdisabled)
 
-      if data["meshbox_"..radio] == '0' then
+      local meshdisabled = 0
+      if data[radio .. '_client_enabled'] == '0' then
         meshdisabled = 1
       end
-
       uci:set('wireless', 'mesh_' .. radio, "disabled", meshdisabled)
 
+      if data[radio .. '_txpower'] then
+        if data[radio .. '_txpower'] == 'default' then
+          uci:delete('wireless', radio, 'txpower')
+        else
+          uci:set('wireless', radio, 'txpower', data[radio .. '_txpower'])
+        end
+      end
+
     end
 
     uci:save('wireless')
diff --git a/package/gluon-luci-wifi-config/i18n/de.po b/package/gluon-luci-wifi-config/i18n/de.po
index 6d51ccf1e..d633d84cb 100644
--- a/package/gluon-luci-wifi-config/i18n/de.po
+++ b/package/gluon-luci-wifi-config/i18n/de.po
@@ -10,6 +10,9 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
+msgid "(default)"
+msgstr "(Standard)"
+
 msgid "2.4GHz WLAN"
 msgstr "2,4GHz-WLAN"
 
@@ -22,11 +25,22 @@ msgstr "Client-Netz aktivieren"
 msgid "Enable mesh network"
 msgstr "Mesh-Netz aktivieren"
 
+msgid "Transmission power"
+msgstr "Sendeleistung"
+
 msgid ""
 "You can enable or disable your node's client and mesh network SSIDs here. "
 "Please don't disable the mesh network without a good reason, so other nodes "
-"can mesh with yours."
+"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
+"adapters transmission power here. Please note that the transmission power "
+"values include the antenna gain where available, but there are many devices "
+"for which the gain is unavailable or inaccurate."
 msgstr ""
-"In diesem Abschnitt hast du die Möglichkeit, die SSIDs des Client- und des "
-"Mesh-Netzes zu aktivieren bzw. deaktivieren. Bitte lass die SSID des Mesh-"
-"Netzes aktiviert, damit sich andere Knoten mit deinem verbinden können."
+"In diesem Abschnitt hast du die Möglichkeit, die SSIDs des Client- und "
+"des Mesh-Netzes zu aktivieren bzw. deaktivieren. Bitte lass die SSID des "
+"Mesh-Netzes aktiviert, damit sich andere Knoten mit deinem verbinden "
+"können.<br /><br />"
+"Außerdem kann hier die Sendeleistung des WLAN-Adapters konfiguriert werden. "
+"Wenn möglich, ist in den Werten der Sendeleistung der Antennengewinn "
+"enthalten; diese Werte sind allerdings für viele Geräte nicht verfügbar oder "
+"fehlerhaft."
diff --git a/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot b/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot
index 52dd7b66c..fa61df184 100644
--- a/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot
+++ b/package/gluon-luci-wifi-config/i18n/gluon-luci-wifi-config.pot
@@ -1,6 +1,9 @@
 msgid ""
 msgstr "Content-Type: text/plain; charset=UTF-8"
 
+msgid "(default)"
+msgstr ""
+
 msgid "2.4GHz WLAN"
 msgstr ""
 
@@ -13,8 +16,14 @@ msgstr ""
 msgid "Enable mesh network"
 msgstr ""
 
+msgid "Transmission power"
+msgstr ""
+
 msgid ""
 "You can enable or disable your node's client and mesh network SSIDs here. "
 "Please don't disable the mesh network without a good reason, so other nodes "
-"can mesh with yours."
+"can mesh with yours.<br /><br />It is also possible to configure the WLAN "
+"adapters transmission power here. Please note that the transmission power "
+"values include the antenna gain where available, but there are many devices "
+"for which the gain is unavailable or inaccurate."
 msgstr ""
-- 
GitLab