-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

-- Description: 系统复位检测

local enums = require 'types.enums'
local skynet = require 'skynet'
local log = require 'mc.logging'
local class = require 'mc.class'
local utils = require 'types.utils'
local lock = false
local c_sys_reset = class()

function c_sys_reset:init()
    -- 私有属性属性变更监听
    self.obj.property_changed:on(function(name, value)
        if name == 'GetSysRstDetected' then
            lock = true
            self:dealwith_sys_reset_detected(value)
            lock = false
        end
    end)
    skynet.fork_once(function()
        if self.obj.GetSysRstDetected == 1 then
            log:notice_easy('[System:%s]init finish and clear GetSysRstDetected flag', self.system_id)
            skynet.sleep(3000) -- 模块初始化后，延迟30s清理复位标志
            self:clear_system_reset()
        end
        self:clear_system_task()
    end)
end

function c_sys_reset:ctor(fructrl, object)
    self.obj = object
    self.fructrl = fructrl
    self.system_id = fructrl.system_id
    log:notice_easy("[System:%s]set sys_reset object successfully, uptime: %s.", self.system_id, utils.uptime())
end

function c_sys_reset:clear_system_task()
    while true do
        skynet.sleep(3000)
        if self.obj.GetSysRstDetected == 1 and not lock then
            self.obj.SetSysRstDetected = 0
        end
    end
end

function c_sys_reset:clear_system_reset()
    log:notice_easy('[System:%s]clear system reset detected', self.system_id)
    local ok, err = pcall(function ()
        for i = 1, 5 do
            self.obj.SetSysRstDetected = 0 -- bmc仅写0, cpld写1
            skynet.sleep(100)
            if self.obj.SetSysRstDetected == 0 then
                break
            else
                log:warn_easy('[System:%s]clear system reset failed,and retry time is %s', self.system_id, i)
            end
        end
    end)
    if not ok then
        log:error('[System:%s]clear system reset flag failed, err:%s', self.system_id, err)
    end
    log:notice_easy('[System:%s]SetSysRstDetected is %s', self.system_id, self.obj.SetSysRstDetected)
end

function c_sys_reset:dealwith_sys_reset_detected(val)
    -- 同步到资源树属性SysResetDetected
    self.fructrl:set_SysResetDetected(val)
    log:notice_easy('[System:%s]detected sys reset %s', self.system_id, val)

    -- 有复位动作时cpld写1，bmc仅做清0操作
    if val ~= 1 then
        return
    end

    self.fructrl.sys_reset_queue(function()
        if not self.fructrl:get_sys_reset_flag() then
            -- 非BMC主动发起的复位
            log:notice_easy('[System:%s]Set Current Restart Cause:Unknown', self.system_id)
            self.fructrl:set_CurrentRestartCause(enums.RestartCause.Unknown)
            skynet.fork_once(function()
                -- 非BMC主动发起的复位记录InitiatedByWarmReset的SEL日志
                self.fructrl:set_CurrentRestartType(enums.RestartInitiateId['InitiatedByWarmReset'])
                skynet.sleep(200) -- 等待2s，等待传感器事件生成后恢复默认值
                self.fructrl:set_CurrentRestartType(enums.RestartInitiateId['None'])
            end)
            log:notice("Current restart cause is changed to Unknown.")
        end
        self.fructrl:set_sys_reset_flag(false)
    end)

    -- 延迟30s再清理复位标志，保证复位能被其他app监听到
    skynet.sleep(3000) -- 延时3000*10ms
    self:clear_system_reset()
end

return c_sys_reset