0
0
mirror of https://github.com/Doodle3D/doodle3d-firmware.git synced 2024-12-22 19:13:49 +01:00

Implement settings interface.

This commit is contained in:
Wouter R 2013-07-17 17:43:33 +02:00
parent 9a8ac55b8f
commit d3e4812cbf
3 changed files with 209 additions and 15 deletions

View File

@ -1,5 +1,8 @@
local M = {}
--NOTE: proposed notation for baseline configuration (containing defaults as well as type and constraint information)
--the table name is the configuration key; min, max and regex are all optional; type is one of: {bool, int, float, string}
--NOTE: pcall protects from invocation exceptions, which is what we need except
--during debugging. This flag replaces them with a normal call so we can inspect stack traces.
M.DEBUG_PCALLS = true
@ -7,28 +10,38 @@ M.DEBUG_PCALLS = true
--REST responses will contain 'module' and 'function' keys describing what was requested
M.API_INCLUDE_ENDPOINT_INFO = false
M.DEFAULT_AP_SSID = "d3d-ap-%MAC_ADDR_TAIL%"
M.DEFAULT_AP_ADDRESS = "192.168.10.1"
M.DEFAULT_AP_NETMASK = "255.255.255.0"
-- was: M.DEFAULT_AP_SSID = "d3d-ap-%MAC_ADDR_TAIL%"
M.apSsid = {
default = 'd3d-ap-%%MAC_ADDR_TAIL%%',
type = 'string',
description = 'Access Point mode SSID',
min = 1,
max = 32
}
-- was: M.DEFAULT_AP_ADDRESS = "192.168.10.1"
M.apAddress = {
default = '192.168.10.1',
type = 'string',
description = 'Access Point mode IP address',
regex = '%d+\.%d+\.%d+\.%d+'
}
-- was: M.DEFAULT_AP_NETMASK = "255.255.255.0"
M.apNetmask = {
default = '255.255.255.0',
type = 'string',
description = 'Access Point mode netmask',
regex = '%d+\.%d+\.%d+\.%d+'
}
--NOTE: proposed notation for baseline configuration (containing defaults as well as type and constraint information)
--the table name is the configuration key; min, max and regex are all optional; type is one of: {int, float, string, ...?}
M.temperature = {
default = 230,
type = 'int',
description = '...xyzzy',
description = '3D printer temperature',
min = 0,
max = 350
}
M.ssid = {
default = 'd3d-ap-%%MAC_TAIL%%',
type = 'int', --one of: {int, float, string, ...?}
min = 1,
max = 32,
regex = '[a-zA-Z0-9 -=+]+'
}
return M

View File

@ -0,0 +1,66 @@
local s = require('util.settings')
local defaults = require('conf_defaults')
local uciConfigFile = '/etc/config/wifibox'
local uciConfigFileBackup = '/etc/config/wifibox.orig'
local M = {
_is_test = true,
_skip = { },
_wifibox_only = { 'get' }
}
function M:_setup()
os.execute('mv -f ' .. uciConfigFile .. ' ' .. uciConfigFileBackup .. ' 2>/dev/null')
end
function M:_teardown()
os.execute('rm -f ' .. uciConfigFile)
os.execute('mv -f ' .. uciConfigFileBackup .. ' ' .. uciConfigFile .. ' 2>/dev/null')
end
function M:test_get()
local realKey, fakeKey = 'apAddress', 'theAnswer'
assert(not s.exists(fakeKey))
local fakeValue = s.get(fakeKey)
assert(fakeValue == nil)
assert(s.exists(realKey))
local realValue = s.get(realKey)
assert(realValue ~= nil)
assert(realValue == defaults.apAddress.default)
end
function M:test_set()
local key = 'apAddress'
local goodValue, badValue1, badValue2 = '10.0.0.1', '10.00.1', '10.0.0d.1'
assert(s.get(key) == defaults.apAddress.default)
assert(s.isDefault(key))
assert(s.set(key, goodValue))
assert(s.get(key) == goodValue)
assert(not s.isDefault(key))
assert(s.set(key, badValue1) == nil)
assert(s.get(key) == goodValue)
assert(s.set(key, badValue2) == nil)
assert(s.get(key) == goodValue)
assert(s.set(key, nil))
assert(s.isDefault(key))
end
function M:test_setNonExistent()
local fakeKey = 'theAnswer'
assert(s.get(fakeKey) == nil)
assert(s.set(fakeKey, 42) == nil)
assert(s.get(fakeKey) == nil)
end
return M

115
src/util/settings.lua Normal file
View File

@ -0,0 +1,115 @@
--[[
This settings interface reads and writes its configuration using UCI.
The corresponding config file is /etc/config/wifibox. To have an initial
set of reasonable settings (and allow users to easily return to them),
any key not found in the UCI configuration is looked up in the (immutable)
'base configuration' (base_config.lua). This file also contains constraints
to check if newly set values are valid.
]]--
local u = require('util.utils')
local baseconfig = require('conf_defaults')
local uci = require('uci').cursor()
local M = {}
local UCI_CONFIG_NAME = 'wifibox' -- the file under /etc/config
local UCI_CONFIG_FILE = '/etc/config/' .. UCI_CONFIG_NAME
local UCI_CONFIG_TYPE = 'settings' -- the section type that will be used in UCI_CONFIG_FILE
local UCI_CONFIG_SECTION = 'general' -- the section name that will be used in UCI_CONFIG_FILE
local ERR_NO_SUCH_KEY = "key does not exist"
local function toUciValue(v, type)
if type == 'bool' then return v and '1' or '0' end
return tostring(v)
end
local function fromUciValue(v, type)
if type == 'bool' then
return (v == '1') and true or false
elseif type == 'float' or type == 'int' then
return tonumber(v)
else
return v
end
end
local function isValid(value, baseTable)
local type, min, max, regex = baseTable.type, baseTable.min, baseTable.max, baseTable.regex
if type == 'bool' then
return isboolean(value) or nil,"invalid bool value"
elseif type == 'int' or type == 'float' then
local ok = isnumber(value)
ok = ok and (type == 'float' or math.floor(value) == value)
if min then ok = ok and value >= min end
if max then ok = ok and value <= max end
return ok or nil,"invalid int/float value"
elseif type == 'string' then
local ok = true
if min then ok = ok and value:len() >= min end
if max then ok = ok and value:len() <= max end
if regex then ok = ok and value:match(regex) ~= nil end
return ok or nil,"invalid string value"
end
return true
end
local function getBaseKeyTable(key)
local base = baseconfig[key]
return type(base) == 'table' and base.default ~= nil and base or nil
end
function M.get(key)
local base = getBaseKeyTable(key)
if not base then return nil,ERR_NO_SUCH_KEY end
local v = base.default
local uciV = fromUciValue(uci:get(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key))
return uciV or v
end
function M.exists(key)
return getBaseKeyTable(key) ~= nil
end
function M.isDefault(key)
if not M.exists(key) then return nil,ERR_NO_SUCH_KEY end
return uci:get(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key) == nil
end
-- pass nil as value to restore default
function M.set(key, value)
local r = u.create(UCI_CONFIG_FILE)
uci:set(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, UCI_CONFIG_TYPE)
local base = getBaseKeyTable(key)
if not base then return nil,ERR_NO_SUCH_KEY end
if M.isDefault(key) and value == nil then return true end -- key is default already
local current = uci:get(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key)
if fromUciValue(current) == value then return true end
if value ~= nil then
local valid,m = isValid(value, base)
if (valid) then
uci:set(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key, toUciValue(value, base.type))
else
return nil,m
end
else
uci:delete(UCI_CONFIG_NAME, UCI_CONFIG_SECTION, key)
end
uci:commit(UCI_CONFIG_NAME)
return true
end
return M