summaryrefslogtreecommitdiff
path: root/files/common/openwrt/sensors.module_lua
diff options
context:
space:
mode:
Diffstat (limited to 'files/common/openwrt/sensors.module_lua')
-rw-r--r--files/common/openwrt/sensors.module_lua173
1 files changed, 173 insertions, 0 deletions
diff --git a/files/common/openwrt/sensors.module_lua b/files/common/openwrt/sensors.module_lua
new file mode 100644
index 00000000..f6c3e38c
--- /dev/null
+++ b/files/common/openwrt/sensors.module_lua
@@ -0,0 +1,173 @@
+local base = _G
+local io = require("io")
+local string = require("string")
+local cjson = require "cjson.safe"
+local glob = require "posix.glob"
+local time = require "posix.time"
+local unistd = require "posix.unistd"
+
+local _M = {}
+local _internal_ = {}
+_internal_.setup = {}
+
+-- ############# i2c ###########
+
+function _internal_.write_to_file(path, data)
+ -- base.print(string.format("writing '%s' to '%s'", data, path))
+ local f, err = io.open(path, "w")
+ if not f then return nil, err end
+
+ ret, err = f:write(data)
+ f:close()
+ return ret, err
+end
+
+function _internal_.read_from_file(path)
+ local f, err = io.open(path, "r")
+ if not f then return nil, err end
+
+ data, err = f:read("*a")
+ f:close()
+ return data, err
+end
+
+-- ############# i2c ###########
+
+function _M.i2c_bus_path(bus)
+ return string.format("/sys/bus/i2c/devices/i2c-%d", bus)
+end
+
+function _M.i2c_device_name(bus, address)
+ return string.format("%d-%04X", bus, address)
+end
+
+function _M.i2c_device_path(bus, address)
+ return string.format("/sys/bus/i2c/devices/" .. _M.i2c_device_name(bus, address))
+end
+
+function _M.i2c_add_device(bus, address, name)
+ return _internal_.write_to_file(_M.i2c_bus_path(bus) .. "/new_device", string.format("%s 0x%02X", name, address))
+end
+
+function _M.i2c_delete_device(bus, address)
+ return _internal_.write_to_file(_M.i2c_bus_path(bus) .. "/delete_device", string.format("0x%02X", address))
+end
+
+function _M.i2c_get_mux_channels(parent, address)
+ local channel_paths, glob_result = glob.glob(_M.i2c_device_path(parent, address) .. "/channel-*", 0)
+ if not channel_paths then
+ if glob_result == glob.GLOB_NOMATCH then return {} end
+ if glob_result == glob.GLOB_ABORTED then return nil, "glob(): aborted" end
+ if glob_result == glob.GLOB_NOSPACE then return nil, "glob(): no space" end
+ return nil, "glob(): unknown error"
+ end
+
+ local channels = {}
+ for _, channel_path in base.pairs(channel_paths) do
+ local channel = string.match(channel_path, '/channel%-(%d+)$')
+ if not channel then return nil, "unable to parse channel number from path: " .. channel_path end
+
+ local bus_path, err = unistd.readlink(channel_path)
+ if not bus_path then return nil, err end
+ local bus = string.match(bus_path, '/i2c%-(%d+)$')
+ if not bus then return nil, "unable to parse bus number from path: " .. bus_path end
+
+ channels[tonumber(channel)] = tonumber(bus)
+ end
+ return channels
+end
+
+function _M.i2c_add_devices_recursive(bus, devices)
+ local num_devices = 0
+ local device
+ for _, device in base.ipairs(devices) do
+ -- base.print(string.format("i2c_add_device(%d, 0x%02X, %s)", bus, device.address, device.driver))
+ _M.i2c_add_device(bus, device.address, device.driver)
+ num_devices = num_devices + 1
+
+ local setup_function = _internal_.setup[device.driver]
+ if setup_function ~= nil then
+ time.nanosleep({tv_sec = 0, tv_nsec = 100000000})
+ setup_function(bus, device.address)
+ end
+
+ if device.channels then
+ time.nanosleep({tv_sec = 0, tv_nsec = 100000000})
+ local mux_channels, err = _M.i2c_get_mux_channels(bus, device.address)
+ if not mux_channels then return nil, error end
+ local channel
+ for _, channel in base.ipairs(device.channels) do
+ if not mux_channels[channel.number] then return nil, string.format("i2c-mux %s has no channel %d", _M.i2c_device_name(bus, device.address), channel.number) end
+ local tmp, err = _M.i2c_add_devices_recursive(mux_channels[channel.number], channel.devices)
+ if not tmp then return nil, err end
+ num_devices = num_devices + tmp
+ end
+ end
+ end
+
+ return num_devices
+end
+
+
+-- ############# II0 ###########
+
+function _M.iio_device_path_from_i2c_device(bus, address)
+ local device_paths, glob_result = glob.glob(_M.i2c_device_path(bus, address) .. "/iio:device*", 0)
+ if not device_paths then
+ if glob_result == glob.GLOB_NOMATCH then return nil, "couldn't find IIO device handle for i2c device " .. _M.i2c_device_name(bus, address) end
+ if glob_result == glob.GLOB_ABORTED then return nil, "glob(): aborted" end
+ if glob_result == glob.GLOB_NOSPACE then return nil, "glob(): no space" end
+ return nil, "glob(): unknown error"
+ end
+ if #device_paths ~= 1 then return nil, "found more than one IIO device for i2c device " .. _M.i2c_device_name(bus, address) end
+ return device_paths[1]
+end
+
+function _M.iio_setup_bmp280(bus, address)
+ local iio_device, err = _M.iio_device_path_from_i2c_device(bus, address)
+ if not iio_device then return nil, err end
+
+ local ret, err = _internal_.write_to_file(iio_device .. '/in_pressure_oversampling_ratio', '1')
+ if not ret then return nil, err end
+ return _internal_.write_to_file(iio_device .. '/in_temp_oversampling_ratio', '1')
+end
+_internal_.setup['bmp280'] = _M.iio_setup_bmp280
+
+function _M.iio_setup_bme280(bus, address)
+ local iio_device, err = _M.iio_device_path_from_i2c_device(bus, address)
+ if not iio_device then return nil, err end
+
+ local ret, err = _internal_.write_to_file(iio_device .. '/in_humidityrelative_oversampling_ratio', '1')
+ if not ret then return nil, err end
+ local ret, err = _internal_.write_to_file(iio_device .. '/in_pressure_oversampling_ratio', '1')
+ if not ret then return nil, err end
+ return _internal_.write_to_file(iio_device .. '/in_temp_oversampling_ratio', '1')
+end
+_internal_.setup['bme280'] = _M.iio_setup_bme280
+
+
+-- ############# config ###########
+
+function _M.read_config(path)
+ sensors_json, err = _internal_.read_from_file(path)
+ if not sensors_json then return nil, err end
+
+ return cjson.decode(sensors_json)
+end
+
+function _M.setup(config)
+ local num_devices = 0
+ if config.i2c then
+ local i2c_bus
+ for _, i2c_bus in ipairs(config.i2c) do
+ local tmp, err = _M.i2c_add_devices_recursive(i2c_bus.number, i2c_bus.devices)
+ if not tmp then return nil, err end
+ num_devices = num_devices + tmp
+ end
+ end
+end
+
+
+-- ################################
+
+return _M