[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