#!/opt/lnxall_app/bin/lua

-- Created by jiaqiang.ye@lnxall.com
-- Simple reset-cause for non-openwrt systems

local bit32 = require "bit32"
local posix = require "posix"
local invoker = require "invoker"

local g_SOFTRST         = "SoftRst\n"
local g_UNKNOWN         = "Unknown\n"
local g_POWERONRST      = "PowerOnRst\n"
local g_WATCHDOGRST     = "WatchdogRst\n"

local function is_rk3568()
	local fdat = invoker.readfile("/proc/cpuinfo")
	if type(fdat) == "string" and string.find(fdat, "Rockchip RK3568", 1, true) then
		return true
	end

	fdat = invoker.readfile("/proc/device-tree/model")
	if type(fdat) == "string" and string.find(fdat, "K3568", 1, true) then
		return true
	end
	return false
end

local function is_rk3588()
	local output = invoker.readfile("/proc/device-tree/model")
	if type(output) ~= "string" then output = "not found" end
	if string.find(output, "RK3588", 1, true) then
		return true
	end
	return false
end

local function is_imx6ul()
	local output = invoker.readfile("/proc/cpuinfo")
	if type(output) ~= "string" then output = "not found" end
	if string.find(output, "i.MX6 Ultralite", 1, true) then
		return true
	end
	return false
end

local function is_ma35d1()
	local output = invoker.readfile("/proc/device-tree/model")
	if type(output) ~= "string" then output = "not found" end
	if string.find(output, "MA35D1", 1, true) then
		return true
	end
	return false
end

local function rk3568_cause()
	local okay, output = invoker.invoke(invoker.OUTPUT + invoker.CLOSEFD,
		"mmap", "read", "0xfdd200e0", "1")

	if okay ~= 0 or type(output) ~= "string" then
		io.stderr:write("Error, failed to execute mmap utility\n")
		io.stderr:flush()
		io.stdout:write("unknown\n")
		io.stdout:flush()
		return false
	end

	if string.find(output, "00000000", 1, true) then
		io.stdout:write(g_POWERONRST)
	else
		io.stdout:write(g_SOFTRST)
	end
	io.stdout:flush()
	return true
end

local function rk3588_cause()
	local okay, output = invoker.invoke(invoker.OUTPUT + invoker.CLOSEFD,
		"mmap", "read", "0xfd7c0c04", "1")

	if okay ~= 0 or type(output) ~= "string" then
		io.stderr:write("Error, failed to execute mmap utility\n")
		io.stderr:flush()
		io.stdout:write("unknown\n")
		io.stdout:flush()
		return false
	end

	if string.find(output, "00000000", 1, true) then
		io.stdout:write(g_POWERONRST)
	else
		io.stdout:write(g_SOFTRST)
	end
	io.stdout:flush()
	return true
end

local function imx6ul_cause()
	if posix.access("/dev/mem") ~= 0 then
		io.stderr:write("Error, /dev/mem not found.\n")
		io.stderr:flush()
		return false
	end

	local okay, output = invoker.invoke(invoker.OUTPUT + invoker.CLOSEFD,
		"mmap", "read", "0x020d8008", "1")

	if okay ~= 0 or type(output) ~= "string" then
		io.stderr:write("Error, failed to execute mmap utility\n")
		io.stderr:flush()
		io.stdout:write(g_UNKNOWN)
		io.stdout:flush()
		return false
	end

	if string.find(output, "00000011", 1, true) or string.find(output, "00000010", 1, true) then
		io.stdout:write(g_WATCHDOGRST)
	else
		io.stdout:write(g_POWERONRST)
	end
	io.stdout:flush()
	return true
end

local function ma35d1_cause()
	local output = invoker.readfile("/tmp/.reg_rststs", invoker.TRIMEND)
	if type(output) ~= "string" or #output == 0 then
		io.stderr:write("Error, failed to execute mmap utility\n")
		io.stderr:flush()
		io.stdout:write(g_UNKNOWN)
		io.stdout:flush()
		return false
	end

	local hexstr = output:match(":%s*(%x+)")
	if not hexstr or hexstr == "" then
		io.stderr:write("Error, maybe rstcause.service execute failed\n")
		io.stderr:flush()
		io.stdout:write(g_UNKNOWN)
		io.stdout:flush()
		return false
	end

	local hexv = tonumber(hexstr, 16)
	if bit32.band(hexv, 0x1) ~= 0 then
		io.stdout:write(g_POWERONRST)
	else
		if bit32.band(hexv, 0x400) ~= 0 then
			io.stdout:write(g_WATCHDOGRST)
		elseif bit32.band(hexv, 0x42) ~= 0 then
			io.stdout:write(g_SOFTRST)
		else
			io.stdout:write(g_UNKNOWN)
			io.stdout:flush()
			return false
		end
	end
	io.stdout:flush()
	return true
end

local function mainfunc()
	posix.setenv('PATH', '/opt/lnxall_app/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin', true)

	if is_rk3568() then
		return rk3568_cause()
	elseif is_imx6ul() then
		return imx6ul_cause()
	elseif is_ma35d1() then
		return ma35d1_cause()
	elseif is_rk3588() then
		return rk3588_cause()
	end

	io.stderr:write("Warning, supported system hardware.\n")
	io.stderr:flush()
	io.stdout:write("unknown\n")
	io.stdout:flush()
	return false
end

mainfunc()
os.exit(0)
