[PATCH] rtl83xx-poe: add package

Birger Koblitz mail at birger-koblitz.de
Wed Mar 10 19:17:06 GMT 2021


Run tested by me on a DGS1210-10P.
Please merge,
   Birger

On 09/03/2021 22:18, Bjørn Mork wrote:
> From: John Crispin <john at phrozen.org>
>
> Signed-off-by: John Crispin <john at phrozen.org>
> Signed-off-by: Bjørn Mork <bjorn at mork.no>
> ---
> This is John's simple PoE daemon for the realtek devices, which has been
> cycling around in assorted repos since last year.  It's well tested by
> now.  I've been running this with constant polling from cacti for a
> few months now without any issues.
>
> I believe this should be included in master to make it easier to find
> and install for new users.
>
>
>
> Bjørn
>
>
>   package/rtl83xx-poe/Makefile             |  29 +++
>   package/rtl83xx-poe/files/bin/poe.lua    | 316 +++++++++++++++++++++++
>   package/rtl83xx-poe/files/etc/config/poe |  10 +
>   package/rtl83xx-poe/files/etc/init.d/poe |  18 ++
>   4 files changed, 373 insertions(+)
>   create mode 100644 package/rtl83xx-poe/Makefile
>   create mode 100755 package/rtl83xx-poe/files/bin/poe.lua
>   create mode 100644 package/rtl83xx-poe/files/etc/config/poe
>   create mode 100755 package/rtl83xx-poe/files/etc/init.d/poe
>
> diff --git a/package/rtl83xx-poe/Makefile b/package/rtl83xx-poe/Makefile
> new file mode 100644
> index 000000000000..195b1eb20949
> --- /dev/null
> +++ b/package/rtl83xx-poe/Makefile
> @@ -0,0 +1,29 @@
> +include $(TOPDIR)/rules.mk
> +
> +PKG_NAME:=rtl83xx-poe
> +PKG_RELEASE:=2
> +
> +PKG_LICENSE:=GPL-2.0+
> +
> +include $(INCLUDE_DIR)/package.mk
> +
> +define Package/rtl83xx-poe
> +  SECTION:=utils
> +  CATEGORY:=Utilities
> +  DEPENDS:=+libubox-lua +libubus-lua +libuci-lua +lua-rs232
> +  TITLE:=PoE daemon for realtek switches
> +endef
> +
> +define Package/rtl83xx-poe/description
> + This package contains an utility to allow triggering the PoE state of realtek switch ports.
> +endef
> +
> +define Build/Compile
> +
> +endef
> +
> +define Package/rtl83xx-poe/install
> +	$(CP) ./files/* $(1)/
> +endef
> +
> +$(eval $(call BuildPackage,rtl83xx-poe))
> diff --git a/package/rtl83xx-poe/files/bin/poe.lua b/package/rtl83xx-poe/files/bin/poe.lua
> new file mode 100755
> index 000000000000..86dafe13cd01
> --- /dev/null
> +++ b/package/rtl83xx-poe/files/bin/poe.lua
> @@ -0,0 +1,316 @@
> +#!/usr/bin/lua
> +local rs = require "luars232"
> +
> +port_name = "/dev/ttyS1"
> +out = io.stderr
> +nseq = 0
> +
> +budget = 65.0
> +port_power = {0, 0, 0, 0, 0, 0, 0, 0 }
> +
> +if arg[1] ~= nil then
> +	budget = tonumber(arg[1])
> +end
> +for i = 1, 8 do
> +	port_power[i] = arg[i + 1]
> +end
> +
> +function initSerial(p)
> +	local e, p = rs.open(p)
> +	if e ~= rs.RS232_ERR_NOERROR then
> +		-- handle error
> +		out:write(string.format("can't open serial port '%s', error: '%s'\n",
> +				port_name, rs.error_tostring(e)))
> +		return
> +	end
> +
> +	assert(p:set_baud_rate(rs.RS232_BAUD_19200) == rs.RS232_ERR_NOERROR)
> +	assert(p:set_data_bits(rs.RS232_DATA_8) == rs.RS232_ERR_NOERROR)
> +	assert(p:set_parity(rs.RS232_PARITY_NONE) == rs.RS232_ERR_NOERROR)
> +	assert(p:set_stop_bits(rs.RS232_STOP_1) == rs.RS232_ERR_NOERROR)
> +	assert(p:set_flow_control(rs.RS232_FLOW_OFF)  == rs.RS232_ERR_NOERROR)
> +
> +	out:write(string.format("OK, port open with values '%s'\n", tostring(p)))
> +
> +	return p
> +end
> +
> +function receive(pCon)
> +	local reply = {}
> +	local retries = 0
> +
> +	while table.getn(reply) < 12 and retries < 4 do
> +		-- Read up to 12 byte response, timeout 400ms
> +		err, data_read, size = pCon:read(12, 400)
> +		assert(err == rs.RS232_ERR_NOERROR)
> +--		io.write(string.format("-> [%2d]:", string.len(data_read)))
> +		for i = 1, string.len(data_read) do
> +			table.insert(reply, string.byte(string.sub(data_read, i, i)))
> +--			io.write(string.format(" %02x", reply[i]))
> +		end
> +--		io.write("\n")
> +		retries = retries + 1
> +	end
> +	if table.getn(reply) ~= 12 then
> +		print ("Unexpected length!")
> +		return(nil)
> +	end
> +	local sum = 0
> +	for i = 1, 11 do
> +		sum = sum + reply[i]
> +	end
> +	if sum % 256 ~= reply[12] then
> +		print ("Checksum error!")
> +		return(nil)
> +	end
> +	return(reply)
> +end
> +
> +function sendCommand(pCon, cmd)
> +	nseq = nseq + 1
> +	cmd[2] = nseq % 256
> +
> +	while table.getn(cmd) < 11 do
> +		table.insert(cmd, 0xff)
> +	end
> +	local c_string = ""
> +	local sum = 0
> +--	io.write("send  ")
> +	for i = 1, 11 do
> +		sum = sum + cmd[i]
> +--		io.write(string.format(" %02x", cmd[i]))
> +		c_string = c_string .. string.char(cmd[i])
> +	end
> +--	io.write(string.format(" %02x\n", sum % 256))
> +	c_string = c_string .. string.char(sum % 256)
> +	err, len_written = pCon:write(c_string)
> +	assert(err == rs.RS232_ERR_NOERROR)
> +
> +	local reply = receive(pCon)
> +	if reply then
> +--		io.write("recv  ")
> +--		dumpReply(reply)
> +		if (reply[1] == cmd[1] and reply[2] == cmd[2]) then
> +			return(reply)
> +		else
> +			if reply[1] == 0xfd then
> +				print ("An incomplete request was received!")
> +			elseif reply[1] == 0xfe then
> +				print ("Request frame checksum was incorrect!")
> +			elseif reply[1] == 0xff then
> +				print ("Controller was not ready to respond !")
> +			else
> +				print ("Sequence number mismatch!")
> +			end
> +		end
> +	else
> +		print ("Missing reply!")
> +	end
> +	return(nil)
> +end
> +
> +function dumpReply(reply)
> +	for i,v in ipairs(reply) do
> +		io.write(string.format(" %02x", v))
> +	end
> +	io.write("\n");
> +end
> +
> +function getStatus(pCon)
> +	local cmd = {0x20, 0x01}
> +	local reply = sendCommand(pCon, cmd)
> +	if not reply then return(nil) end
> +	-- returns status, PoEExtVersion, PoEVersion, state2
> +	return({reply[5], reply[6], reply[7], reply[10]})
> +end
> +
> +function disablePort(pCon, port)
> +	local cmd = {0x00, port, port, 0x00}
> +	-- disable command is always sent twice
> +	sendCommand(pCon, cmd)
> +	sendCommand(pCon, cmd)
> +end
> +
> +function enablePort(pCon, port)
> +	local cmd = {0x00, port, port, 0x01}
> +	sendCommand(pCon, cmd)
> +end
> +
> +function setPortRelPrio(pCon, port, prio)
> +	local cmd = {0x1d, 0x00, port, prio}
> +	sendCommand(pCon, cmd)
> +end
> +
> +function setGlobalPowerBudget(pCon, maxPower, guard)
> +	-- maxPower and guard Watts
> +	local cmd = {0x18, 0x01, 0x00}
> +	table.insert(cmd, math.floor(maxPower * 10 / 256))
> +	table.insert(cmd, math.floor(maxPower * 10) % 256)
> +	table.insert(cmd, math.floor(guard * 10 / 256))
> +	table.insert(cmd, math.floor(guard * 10) % 256)
> +	sendCommand(pCon, cmd)
> +end
> +
> +function setPowerLowAction(pCon, disableNext)
> +	local cmd = {0x17, 0x00}
> +	if disableNext then
> +		table.insert(cmd, 0x04)
> +	else
> +		table.insert(cmd, 0x02)
> +	end
> +	sendCommand(pCon, cmd)
> +end
> +
> +function getPowerStat(pCon)
> +	local cmd = {0x23, 0x01}
> +	local reply = sendCommand(pCon, cmd)
> +	if not reply then return(nil) end
> +	local watts = (reply[3] * 256 + reply[4]) / 10.0
> +	return watts
> +end
> +
> +function getPortPower(pCon, port)
> +	local cmd = {0x30, 0x01, port}
> +	local reply = sendCommand(pCon, cmd)
> +	if not reply then return(nil) end
> +	local watts = (reply[10] * 256 + reply[11]) / 10.0
> +	local mamps = reply[6] * 256 + reply[7]
> +	return({watts, mamps})
> +end
> +
> +function getPortOverview(pCon)
> +	local cmd = {0x2a, 0x01, 0x00}
> +	local reply = sendCommand(pCon, cmd)
> +	if not reply then return(nil) end
> +	local s = { }
> +	for i = 4, 11 do
> +		if reply[i] == 0x10 then
> +			s[i-3] = "off"
> +		elseif reply[i] == 0x11 then
> +			s[i-3] = "enabled"
> +		elseif reply[i] > 0x11 then
> +			s[i-3] = "active"
> +		else
> +			s[i-3] = "unknown"
> +		end
> +	end
> +	return(s)
> +end
> +
> +-- Priority for power: 3: High, 2: Normal, 1: Low?
> +function setPortPriority(pCon, port, prio)
> +	local cmd = {0x1a, port, port, prio}
> +	local reply = sendCommand(pCon, cmd)
> +	if not reply then return(nil) end
> +	return(unpack(reply, 4, 11))
> +end
> +
> +function getPortPowerLimits(pCon, port)
> +	local cmd = {0x26, 0x01, port}
> +	local reply = sendCommand(pCon, cmd)
> +	if not reply then return(nil) end
> +	return(reply)
> +end
> +
> +function startupPoE(pCon)
> +	local reply = nil
> +	reply = getStatus(pCon)
> +
> +	setGlobalPowerBudget(pCon, 0, 0)
> +	setPowerLowAction(pCon, nil)
> +	-- do something unknown
> +	sendCommand(pCon, {0x06, 0x00, 0x01})
> +	for i = 0, 7 do
> +		if port_power[i + 1] ~= "1" then
> +			disablePort(pCon, i)
> +		end
> +	end
> +	-- do something unknown
> +	sendCommand(pCon, {0x02, 0x00, 0x01})
> +
> +	for i = 0, 7 do
> +		if port_power[i + 1] ~= "1" then
> +			disablePort(pCon, i)
> +		end
> +	end
> +	-- do something unknown
> +	sendCommand(pCon, {0x02, 0x00, 0x01})
> +
> +	-- use monitor command 25
> +	sendCommand(pCon, {0x25, 0x01})
> +
> +	setGlobalPowerBudget(pCon, 65.0, 7.0)
> +	getPowerStat(pCon)
> +	-- -> 23 01 00 00 02 44 00 02 ff ff 00 6a
> +
> +	-- Set 4 unknown port properties:
> +	for i = 0, 7 do
> +		sendCommand(pCon, {0x11, i, i, 0x01})
> +		sendCommand(pCon, {0x13, i, i, 0x02})
> +		sendCommand(pCon, {0x15, i, i, 0x01})
> +		sendCommand(pCon, {0x10, i, i, 0x03})
> +	end
> +	for i = 0, 7 do
> +		if port_power[i + 1] == "1" then
> +			enablePort(pCon, i)
> +		end
> +	end
> +
> +end
> +
> +local p = initSerial(port_name)
> +startupPoE(p)
> +
> +require "ubus"
> +require "uloop"
> +
> +uloop.init()
> +
> +local conn = ubus.connect()
> +if not conn then
> +        error("Failed to connect to ubus")
> +end
> +
> +local my_method = {
> +	poe = {
> +		info = {
> +			function(req, msg)
> +				local reply = {}
> +
> +				reply.power_consumption = tostring(getPowerStat(p)).."W"
> +				reply.power_budget = tostring(budget).."W"
> +
> +				reply.ports = {}
> +				local s = getPortOverview(p)
> +				for i = 1, 8 do
> +					if s[i] == "active" then
> +						local r = getPortPower(p, i - 1)
> +						reply.ports[i] = tostring(r[1]).."W"
> +					else
> +						reply.ports[i] = s[i]
> +					end
> +				end
> +				conn:reply(req, reply);
> +			end, {}
> +		},
> +		port = {
> +			function(req, msg)
> +				local reply = {}
> +				if msg.port < 1 or msg.port > 8 then
> +					conn:reply(req, false);
> +					return -1
> +				end
> +				if msg.enable == true then
> +					enablePort(p, msg.port - 1)
> +				else
> +					disablePort(p, msg.port - 1)
> +				end
> +				conn:reply(req, reply);
> +			end, {port = ubus.INT32, enable = ubus.BOOLEAN }
> +		},
> +	},
> +}
> +
> +conn:add(my_method)
> +
> +uloop.run()
> diff --git a/package/rtl83xx-poe/files/etc/config/poe b/package/rtl83xx-poe/files/etc/config/poe
> new file mode 100644
> index 000000000000..4fc9723c88c7
> --- /dev/null
> +++ b/package/rtl83xx-poe/files/etc/config/poe
> @@ -0,0 +1,10 @@
> +config poe poe
> +	option budget	65
> +	option port1	0
> +	option port2	0
> +	option port3	0
> +	option port4	0
> +	option port5	0
> +	option port6	0
> +	option port7	0
> +	option port8	0
> diff --git a/package/rtl83xx-poe/files/etc/init.d/poe b/package/rtl83xx-poe/files/etc/init.d/poe
> new file mode 100755
> index 000000000000..159340b03a38
> --- /dev/null
> +++ b/package/rtl83xx-poe/files/etc/init.d/poe
> @@ -0,0 +1,18 @@
> +#!/bin/sh /etc/rc.common
> +START=40
> +
> +USE_PROCD=1
> +PROG=/bin/poe.lua
> +
> +start_service() {
> +	local budget=$(uci get poe.poe.budget)
> +
> +	procd_open_instance
> +	procd_set_param command "$PROG"
> +	procd_append_param command ${budget:-65}
> +	for p in `seq 1 8`; do
> +		local pwr=$(uci get poe.poe.port$p)
> +		procd_append_param command  ${pwr:-0}
> +	done
> +	procd_close_instance
> +}




More information about the openwrt-devel mailing list