Merge pull request #1329 from mweinelt/outdoor_mode
gluon-core: add outdoor channel support for 5 ghz radios
This commit is contained in:
commit
ddb11ddd69
@ -61,6 +61,7 @@
|
|||||||
-- for channel.
|
-- for channel.
|
||||||
wifi5 = {
|
wifi5 = {
|
||||||
channel = 44,
|
channel = 44,
|
||||||
|
outdoor_chanlist = '100-140',
|
||||||
ap = {
|
ap = {
|
||||||
ssid = 'alpha-centauri.freifunk.net',
|
ssid = 'alpha-centauri.freifunk.net',
|
||||||
},
|
},
|
||||||
|
@ -166,6 +166,25 @@ wifi24 \: optional
|
|||||||
wifi5 \: optional
|
wifi5 \: optional
|
||||||
Same as `wifi24` but for the 5Ghz radio.
|
Same as `wifi24` but for the 5Ghz radio.
|
||||||
|
|
||||||
|
Additionally a range of channels that are safe to use outsides on the 5 GHz band can
|
||||||
|
be set up through ``outdoor_chanlist``, which allows for a space-seperated list of
|
||||||
|
channels and channel ranges, seperated by a hyphen.
|
||||||
|
When set this offers the outdoor mode flag for 5 GHz radios in the config mode which
|
||||||
|
reconfigures the AP to select its channel from outdoor chanlist, while respecting
|
||||||
|
regulatory specifications, and disables mesh on that radio.
|
||||||
|
The ``outdoors`` option in turn allows to configure when outdoor mode will be enabled.
|
||||||
|
When set to ``true`` all 5 GHz radios will use outdoor channels, while on ``false``
|
||||||
|
the outdoor mode will be completely disabled. The default setting is ``'preset'``,
|
||||||
|
which will enable outdoor mode automatically on outdoor-capable devices.
|
||||||
|
::
|
||||||
|
|
||||||
|
wifi5 = {
|
||||||
|
channel = 44,
|
||||||
|
outdoor_chanlist = "100-140",
|
||||||
|
|
||||||
|
[...]
|
||||||
|
},
|
||||||
|
|
||||||
next_node \: package
|
next_node \: package
|
||||||
Configuration of the local node feature of Gluon
|
Configuration of the local node feature of Gluon
|
||||||
::
|
::
|
||||||
|
@ -3,7 +3,8 @@ nodefault 'web-wizard'
|
|||||||
packages 'web-wizard' \
|
packages 'web-wizard' \
|
||||||
'gluon-config-mode-hostname' \
|
'gluon-config-mode-hostname' \
|
||||||
'gluon-config-mode-geo-location' \
|
'gluon-config-mode-geo-location' \
|
||||||
'gluon-config-mode-contact-info'
|
'gluon-config-mode-contact-info' \
|
||||||
|
'gluon-config-mode-outdoor'
|
||||||
|
|
||||||
packages 'web-wizard & autoupdater' \
|
packages 'web-wizard & autoupdater' \
|
||||||
'gluon-config-mode-autoupdater'
|
'gluon-config-mode-autoupdater'
|
||||||
|
13
package/gluon-config-mode-outdoor/Makefile
Normal file
13
package/gluon-config-mode-outdoor/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=gluon-config-mode-outdoor
|
||||||
|
PKG_VERSION:=1
|
||||||
|
|
||||||
|
include ../gluon.mk
|
||||||
|
|
||||||
|
define Package/gluon-config-mode-outdoor
|
||||||
|
TITLE:=UI for displaying & changing the outdoor mode flag in the wizard
|
||||||
|
DEPENDS:=+gluon-config-mode-core
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackageGluon,gluon-config-mode-outdoor))
|
9
package/gluon-config-mode-outdoor/i18n/de.po
Normal file
9
package/gluon-config-mode-outdoor/i18n/de.po
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
msgid ""
|
||||||
|
"Please enable this option in case the node is to be installed outdoors "
|
||||||
|
"to comply with local frequency regulations."
|
||||||
|
msgstr ""
|
||||||
|
"Wenn der Knoten im Freien aufgestellt werden soll, dann aktiviere bitte "
|
||||||
|
"diese Option um den örtlichen Frequenzbestimmungen zu entsprechen."
|
||||||
|
|
||||||
|
msgid "Node will be installed outdoors"
|
||||||
|
msgstr "Knoten wird im Außenbereich betrieben"
|
@ -0,0 +1,7 @@
|
|||||||
|
msgid ""
|
||||||
|
"Please enable this option in case the node is to be installed outdoors "
|
||||||
|
"to comply with local frequency regulations."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Node will be installed outdoors"
|
||||||
|
msgstr ""
|
@ -0,0 +1,28 @@
|
|||||||
|
return function(form, uci)
|
||||||
|
local platform_info = require 'platform_info'
|
||||||
|
|
||||||
|
if not platform_info.is_outdoor_device() then
|
||||||
|
-- only visible on wizard for outdoor devices
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local pkg_i18n = i18n 'gluon-config-mode-outdoor'
|
||||||
|
|
||||||
|
local section = form:section(Section, nil, pkg_i18n.translate(
|
||||||
|
"Please enable this option in case the node is to be installed outdoors "
|
||||||
|
.. "to comply with local frequency regulations."
|
||||||
|
))
|
||||||
|
|
||||||
|
local outdoor = section:option(Flag, 'outdoor', pkg_i18n.translate("Node will be installed outdoors"))
|
||||||
|
outdoor.default = outdoor_mode
|
||||||
|
|
||||||
|
function outdoor:write(data)
|
||||||
|
if data ~= outdoor_mode then
|
||||||
|
uci:set('gluon', 'wireless', 'outdoor', data)
|
||||||
|
uci:save('gluon')
|
||||||
|
os.execute('/lib/gluon/upgrade/200-wireless')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {'gluon', 'wireless'}
|
||||||
|
end
|
@ -33,7 +33,19 @@ for _, config in ipairs({'wifi24', 'wifi5'}) do
|
|||||||
if need_table({config}, nil, false) then
|
if need_table({config}, nil, false) then
|
||||||
need_string(in_site({'regdom'})) -- regdom is only required when wifi24 or wifi5 is configured
|
need_string(in_site({'regdom'})) -- regdom is only required when wifi24 or wifi5 is configured
|
||||||
|
|
||||||
need_number({config, 'channel'})
|
if config == "wifi24" then
|
||||||
|
local channels = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
|
||||||
|
need_one_of({config, 'channel'}, channels)
|
||||||
|
elseif config == 'wifi5' then
|
||||||
|
local channels = {
|
||||||
|
34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
|
||||||
|
64, 96, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118,
|
||||||
|
120, 122, 124, 126, 128, 132, 134, 136, 138, 140, 142, 144,
|
||||||
|
149, 151, 153, 155, 157, 159, 161, 165, 169, 173 }
|
||||||
|
need_one_of({config, 'channel'}, channels)
|
||||||
|
need_chanlist({config, 'outdoor_chanlist'}, channels, false)
|
||||||
|
need_one_of({config, 'outdoors'}, {true, false, 'preset'}, false)
|
||||||
|
end
|
||||||
|
|
||||||
obsolete({config, 'supported_rates'}, '802.11b rates are disabled by default.')
|
obsolete({config, 'supported_rates'}, '802.11b rates are disabled by default.')
|
||||||
obsolete({config, 'basic_rate'}, '802.11b rates are disabled by default.')
|
obsolete({config, 'basic_rate'}, '802.11b rates are disabled by default.')
|
||||||
|
35
package/gluon-core/luasrc/lib/gluon/upgrade/180-outdoors
Executable file
35
package/gluon-core/luasrc/lib/gluon/upgrade/180-outdoors
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/lua
|
||||||
|
|
||||||
|
-- This script needs to be sorted before 200-wireless as it affects
|
||||||
|
-- wireless channel selection and wireless mesh configuration.
|
||||||
|
|
||||||
|
local uci = require('simple-uci').cursor()
|
||||||
|
local site = require 'gluon.site'
|
||||||
|
|
||||||
|
if uci:get('gluon', 'wireless', 'outdoor') ~= nil then
|
||||||
|
-- don't overwrite existing configuration
|
||||||
|
os.exit(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sysconfig = require 'gluon.sysconfig'
|
||||||
|
local platform_info = require 'platform_info'
|
||||||
|
|
||||||
|
local config = site.wifi5.outdoor_preset('preset')
|
||||||
|
local outdoor = false
|
||||||
|
|
||||||
|
if sysconfig.gluon_version then
|
||||||
|
-- don't enable the outdoor mode after an upgrade
|
||||||
|
outdoor = false
|
||||||
|
elseif config == 'preset' then
|
||||||
|
-- enable outdoor mode through presets on new installs
|
||||||
|
outdoor = platform_info.is_outdoor_device()
|
||||||
|
else
|
||||||
|
-- enable/disable outdoor mode unconditionally on new installs
|
||||||
|
outdoor = config
|
||||||
|
end
|
||||||
|
|
||||||
|
uci:section('gluon', 'wireless', 'wireless', {
|
||||||
|
outdoor = outdoor
|
||||||
|
})
|
||||||
|
|
||||||
|
uci:save('gluon')
|
@ -49,22 +49,37 @@ if not sysconfig.gluon_version then
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function is_outdoor()
|
||||||
|
return uci:get_bool('gluon', 'wireless', 'outdoor')
|
||||||
|
end
|
||||||
|
|
||||||
local function get_channel(radio, config)
|
local function get_channel(radio, config)
|
||||||
local channel
|
local channel
|
||||||
if uci:get_first('gluon-core', 'wireless', 'preserve_channels') then
|
if uci:get_first('gluon-core', 'wireless', 'preserve_channels') then
|
||||||
|
-- preserved channel always wins
|
||||||
channel = radio.channel
|
channel = radio.channel
|
||||||
|
elseif (radio.hwmode == '11a' or radio.hwmode == '11na') and is_outdoor() then
|
||||||
|
-- actual channel will be picked and probed from chanlist
|
||||||
|
channel = 'auto'
|
||||||
end
|
end
|
||||||
|
|
||||||
return channel or config.channel()
|
return channel or config.channel()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_htmode(radio)
|
local function get_htmode(radio)
|
||||||
|
if (radio.hwmode == '11a' or radio.hwmode == '11na') and is_outdoor() then
|
||||||
|
local outdoor_htmode = uci:get('gluon', 'wireless', 'outdoor_' .. radio['.name'] .. '_htmode')
|
||||||
|
if outdoor_htmode ~= nil then
|
||||||
|
return outdoor_htmode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local phy = util.find_phy(radio)
|
local phy = util.find_phy(radio)
|
||||||
if iwinfo.nl80211.hwmodelist(phy).ac then
|
if iwinfo.nl80211.hwmodelist(phy).ac then
|
||||||
return 'VHT20'
|
return 'VHT20'
|
||||||
else
|
|
||||||
return 'HT20'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return 'HT20'
|
||||||
end
|
end
|
||||||
|
|
||||||
local function is_disabled(name)
|
local function is_disabled(name)
|
||||||
@ -207,13 +222,29 @@ util.foreach_radio(uci, function(radio, index, config)
|
|||||||
uci:set('wireless', radio_name, 'htmode', htmode)
|
uci:set('wireless', radio_name, 'htmode', htmode)
|
||||||
uci:set('wireless', radio_name, 'country', site.regdom())
|
uci:set('wireless', radio_name, 'country', site.regdom())
|
||||||
|
|
||||||
|
uci:delete('wireless', radio_name, 'supported_rates')
|
||||||
|
uci:delete('wireless', radio_name, 'basic_rate')
|
||||||
|
|
||||||
local hwmode = radio.hwmode
|
local hwmode = radio.hwmode
|
||||||
if hwmode == '11g' or hwmode == '11ng' then
|
if hwmode == '11g' or hwmode == '11ng' then
|
||||||
uci:set('wireless', radio_name, 'legacy_rates', false)
|
uci:set('wireless', radio_name, 'legacy_rates', false)
|
||||||
end
|
elseif (hwmode == '11a' or hwmode == '11na') then
|
||||||
|
if is_outdoor() then
|
||||||
|
uci:set('wireless', radio_name, 'channels', config.outdoor_chanlist())
|
||||||
|
|
||||||
uci:delete('wireless', radio_name, 'supported_rates')
|
-- enforce outdoor channels by filtering the regdom for outdoor channels
|
||||||
uci:delete('wireless', radio_name, 'basic_rate')
|
local hostapd_options = uci:get_list('wireless', radio_name, 'hostapd_options')
|
||||||
|
util.add_to_set(hostapd_options, 'country3=0x4f')
|
||||||
|
uci:set_list('wireless', radio_name, 'hostapd_options', hostapd_options)
|
||||||
|
|
||||||
|
uci:delete('wireless', 'ibss_' .. radio_name)
|
||||||
|
uci:delete('wireless', 'mesh_' .. radio_name)
|
||||||
|
else
|
||||||
|
uci:delete('wireless', radio_name, 'channels')
|
||||||
|
|
||||||
|
local hostapd_options = uci:get_list('wireless', radio_name, 'hostapd_options')
|
||||||
|
util.remove_from_set(hostapd_options, 'country3=0x4f')
|
||||||
|
uci:set_list('wireless', radio_name, 'hostapd_options', hostapd_options)
|
||||||
|
|
||||||
local ibss_disabled = is_disabled('ibss_' .. radio_name)
|
local ibss_disabled = is_disabled('ibss_' .. radio_name)
|
||||||
local mesh_disabled = is_disabled('mesh_' .. radio_name)
|
local mesh_disabled = is_disabled('mesh_' .. radio_name)
|
||||||
@ -232,6 +263,8 @@ util.foreach_radio(uci, function(radio, index, config)
|
|||||||
config.mesh.disabled(false)
|
config.mesh.disabled(false)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
fixup_wan(radio, index)
|
fixup_wan(radio, index)
|
||||||
end)
|
end)
|
||||||
|
@ -27,3 +27,23 @@ function match(target, subtarget, boards)
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function is_outdoor_device()
|
||||||
|
if match('ar71xx', 'generic', {
|
||||||
|
'cpe510-520-v1',
|
||||||
|
'ubnt-nano-m',
|
||||||
|
'ubnt-nano-m-xw',
|
||||||
|
}) then
|
||||||
|
return true
|
||||||
|
|
||||||
|
elseif match('ar71xx', 'generic', {'unifiac-lite'}) and
|
||||||
|
get_model() == 'Ubiquiti UniFi-AC-MESH' then
|
||||||
|
return true
|
||||||
|
|
||||||
|
elseif match('ar71xx', 'generic', {'unifiac-pro'}) and
|
||||||
|
get_model() == 'Ubiquiti UniFi-AC-MESH-PRO' then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
@ -49,3 +49,25 @@ msgstr ""
|
|||||||
"werden. Wenn möglich, ist in den Werten der Sendeleistung der Antennengewinn "
|
"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 "
|
"enthalten; diese Werte sind allerdings für viele Geräte nicht verfügbar oder "
|
||||||
"fehlerhaft."
|
"fehlerhaft."
|
||||||
|
|
||||||
|
msgid "Outdoor installation"
|
||||||
|
msgstr "Outdoor-Installation"
|
||||||
|
|
||||||
|
msgid "Node will be installed outdoors"
|
||||||
|
msgstr "Knoten wird im Außenbereich betrieben"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
|
||||||
|
"and transmission power that conforms with the local regulatory requirements. "
|
||||||
|
"It also enables dynamic frequency selection (DFS; radar detection). At the "
|
||||||
|
"same time, mesh functionality is disabled as it requires neighbouring nodes "
|
||||||
|
"to stay on the same channel permanently."
|
||||||
|
msgstr ""
|
||||||
|
"Ist der Knoten für den Einsatz im Freien konfiguriert, wird ein WLAN-Kanal auf "
|
||||||
|
"dem 5-GHz-Band sowie eine Sendeleistung entsprechend den gesetzlichen "
|
||||||
|
"Frequenzregulatorien gewählt. Gleichzeitig wird die dynamische Frequenzwahl "
|
||||||
|
"(DFS; Radarerkennung) aktiviert und die Mesh-Funktionalität deaktiviert, da "
|
||||||
|
"sich Nachbarknoten dauerhaft auf demselben Kanal befinden müssen."
|
||||||
|
|
||||||
|
msgid "HT Mode"
|
||||||
|
msgstr "HT-Modus"
|
||||||
|
@ -46,3 +46,9 @@ msgstr ""
|
|||||||
"<br /><br />Ici vous pouvez aussi configurer la puissance d'émmission se votre Wi-Fi. "
|
"<br /><br />Ici vous pouvez aussi configurer la puissance d'émmission se votre Wi-Fi. "
|
||||||
"Prenez note que les valeurs fournies pour la puissance de transmission prennent "
|
"Prenez note que les valeurs fournies pour la puissance de transmission prennent "
|
||||||
"en compte les gains fournis par l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
|
"en compte les gains fournis par l'antenne, et que ces valeurs ne sont pas toujours disponibles ou exactes."
|
||||||
|
|
||||||
|
msgid "Outdoor installation"
|
||||||
|
msgstr "Installation extérieure"
|
||||||
|
|
||||||
|
msgid "HT Mode"
|
||||||
|
msgstr "Mode HT"
|
||||||
|
@ -33,3 +33,20 @@ msgid ""
|
|||||||
"values include the antenna gain where available, but there are many devices "
|
"values include the antenna gain where available, but there are many devices "
|
||||||
"for which the gain is unavailable or inaccurate."
|
"for which the gain is unavailable or inaccurate."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Outdoor installation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Node will be installed outdoors"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
|
||||||
|
"and transmission power that conforms with the local regulatory requirements. "
|
||||||
|
"It also enables dynamic frequency selection (DFS; radar detection). At the "
|
||||||
|
"same time, mesh functionality is disabled as it requires neighbouring nodes "
|
||||||
|
"to stay on the same channel permanently."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "HT Mode"
|
||||||
|
msgstr ""
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
local iwinfo = require 'iwinfo'
|
local iwinfo = require 'iwinfo'
|
||||||
|
local site = require 'gluon.site'
|
||||||
local uci = require("simple-uci").cursor()
|
local uci = require("simple-uci").cursor()
|
||||||
local util = require 'gluon.util'
|
local util = require 'gluon.util'
|
||||||
|
|
||||||
@ -8,7 +9,6 @@ local function txpower_list(phy)
|
|||||||
local off = tonumber(iwinfo.nl80211.txpower_offset(phy)) or 0
|
local off = tonumber(iwinfo.nl80211.txpower_offset(phy)) or 0
|
||||||
local new = { }
|
local new = { }
|
||||||
local prev = -1
|
local prev = -1
|
||||||
local _, val
|
|
||||||
for _, val in ipairs(list) do
|
for _, val in ipairs(list) do
|
||||||
local dbm = val.dbm + off
|
local dbm = val.dbm + off
|
||||||
local mw = math.floor(10 ^ (dbm / 10))
|
local mw = math.floor(10 ^ (dbm / 10))
|
||||||
@ -24,6 +24,17 @@ local function txpower_list(phy)
|
|||||||
return new
|
return new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function has_5ghz_radio()
|
||||||
|
local result = false
|
||||||
|
uci:foreach('wireless', 'wifi-device', function(config)
|
||||||
|
local radio = config['.name']
|
||||||
|
local hwmode = uci:get('wireless', radio, 'hwmode')
|
||||||
|
|
||||||
|
result = result or (hwmode == '11a' or hwmode == '11na')
|
||||||
|
end)
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
local f = Form(translate("WLAN"))
|
local f = Form(translate("WLAN"))
|
||||||
|
|
||||||
@ -97,7 +108,57 @@ uci:foreach('wireless', 'wifi-device', function(config)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
if has_5ghz_radio() then
|
||||||
|
local r = f:section(Section, translate("Outdoor Installation"), translate(
|
||||||
|
"Configuring the node for outdoor use tunes the 5 GHz radio to a frequency "
|
||||||
|
.. "and transmission power that conforms with the local regulatory requirements. "
|
||||||
|
.. "It also enables dynamic frequency selection (DFS; radar detection). At the "
|
||||||
|
.. "same time, mesh functionality is disabled as it requires neighbouring nodes "
|
||||||
|
.. "to stay on the same channel permanently."
|
||||||
|
))
|
||||||
|
|
||||||
|
local outdoor = r:option(Flag, 'outdoor', translate("Node will be installed outdoors"))
|
||||||
|
outdoor.default = uci:get_bool('gluon', 'wireless', 'outdoor')
|
||||||
|
|
||||||
|
function outdoor:write(data)
|
||||||
|
uci:set('gluon', 'wireless', 'outdoor', data)
|
||||||
|
end
|
||||||
|
|
||||||
|
uci:foreach('wireless', 'wifi-device', function(config)
|
||||||
|
local radio = config['.name']
|
||||||
|
local hwmode = uci:get('wireless', radio, 'hwmode')
|
||||||
|
|
||||||
|
if hwmode ~= '11a' and hwmode ~= '11na' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local phy = util.find_phy(uci:get_all('wireless', radio))
|
||||||
|
|
||||||
|
local ht = r:option(ListValue, 'outdoor_htmode', translate('HT Mode') .. ' (' .. radio .. ')')
|
||||||
|
ht:depends(outdoor, true)
|
||||||
|
ht.default = uci.get('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode') or 'default'
|
||||||
|
|
||||||
|
ht:value('default', translate("(default)"))
|
||||||
|
for mode, available in pairs(iwinfo.nl80211.htmodelist(phy)) do
|
||||||
|
if available then
|
||||||
|
ht:value(mode, mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ht:write(data)
|
||||||
|
if data == 'default' then
|
||||||
|
data = nil
|
||||||
|
end
|
||||||
|
uci:set('gluon', 'wireless', 'outdoor_' .. radio .. '_htmode', data)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function f:write()
|
function f:write()
|
||||||
|
uci:commit('gluon')
|
||||||
|
os.execute('/lib/gluon/upgrade/200-wireless')
|
||||||
uci:commit('wireless')
|
uci:commit('wireless')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -203,6 +203,33 @@ function alternatives(...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function check_chanlist(channels)
|
||||||
|
local is_valid_channel = check_one_of(channels)
|
||||||
|
return function(chanlist)
|
||||||
|
for group in chanlist:gmatch("%S+") do
|
||||||
|
if group:match("^%d+$") then
|
||||||
|
channel = tonumber(group)
|
||||||
|
if not is_valid_channel(channel) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
elseif group:match("^%d+-%d+$") then
|
||||||
|
from, to = group:match("^(%d+)-(%d+)$")
|
||||||
|
from = tonumber(from)
|
||||||
|
to = tonumber(to)
|
||||||
|
if from >= to then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not is_valid_channel(from) or not is_valid_channel(to) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function need(path, check, required, msg)
|
function need(path, check, required, msg)
|
||||||
local val = loadvar(path)
|
local val = loadvar(path)
|
||||||
if required == false and val == nil then
|
if required == false and val == nil then
|
||||||
@ -307,6 +334,12 @@ function need_array_of(path, array, required)
|
|||||||
return need_array(path, function(e) need_one_of(e, array) end, required)
|
return need_array(path, function(e) need_one_of(e, array) end, required)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function need_chanlist(path, channels, required)
|
||||||
|
local valid_chanlist = check_chanlist(channels)
|
||||||
|
return need(path, valid_chanlist, required, 'be a space-separated list of WiFi channels or channel-ranges (separated by a hyphen). ' ..
|
||||||
|
'Valid channels are: ' .. array_to_string(channels))
|
||||||
|
end
|
||||||
|
|
||||||
function need_domain_name(path)
|
function need_domain_name(path)
|
||||||
need_string(path)
|
need_string(path)
|
||||||
need(path, function(domain_name)
|
need(path, function(domain_name)
|
||||||
|
Loading…
Reference in New Issue
Block a user