-- 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.
local canbus_base = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus'
local log = require 'mc.logging'
local E_OK = nil -- 函数执行成功返回nil

local QUERY_INFO_OK<const> = 0
local QUERY_INFO_FAIL<const> = 1
local function get_pbit(val)
    return 1 << val
end

return function (obj)
    local psu_slot = canbus_base(obj)

    function psu_slot:refresh_batch_query_info()
        -- 0x40 批量查询信息
        local batch_query_info = self.protocol['refresh_batch_query_info']
        local batch_query_info_ok, batch_query_info_resp = pcall(batch_query_info, self.protocol)
        if batch_query_info_ok then
            log:info('[power_mgmt]ps%d refresh_batch_query_info ok', self.ps_id)
            for prop, value in pairs(batch_query_info_resp) do
                self:dal_refresh_property(prop, value)
            end
            self:health_check(batch_query_info_resp)
            self.protocol:canbus_ms_channel_switch(QUERY_INFO_OK)
        else
            self.protocol:canbus_ms_channel_switch(QUERY_INFO_FAIL)
            log:error('[power_mgmt]ps%s refresh_batch_query_info failed, response = %s', self.ps_id,
                        batch_query_info_resp)
        end
    end

    function psu_slot:update_health_event(alarm_status)
        if not alarm_status then
            return {}
        end
        local event = 0
        -- 输出过压
        local output_over_voltage = alarm_status & get_pbit(0)
        if output_over_voltage > 0 then
            -- 根据canbus协议AlarmStatus属性bit0为1，代表输出过压。但是根据电源告警，若输出过压，OutputVoltageFault bit7需要置为1
            output_over_voltage = get_pbit(7)
        end

        -- 过温
        local over_temper_fault = alarm_status & get_pbit(1)
        if over_temper_fault > 0 then
            -- 根据canbus协议AlarmStatus属性bit16为1，代表过温。但是根据电源告警，若过温，OverTemperature bit7需要置为1
            over_temper_fault = get_pbit(7)
            event = event | get_pbit(3)
        end

        return {
            event = event,
            output_voltage_fault = output_over_voltage,
            temper_fault = over_temper_fault,
        }
    end

    function psu_slot:update_communication_status()
        local ok, _
        if self.refresh_info_nums < 10 then
            return
        end
        self.refresh_info_nums = 0
        ok, _ = pcall(function()
            return self.protocol:can_get_canbus_basic_info()
        end)
        if not ok then
            if self.read_fail_count < 4 then
                self.read_fail_count = self.read_fail_count + 1
            else
                self:dal_refresh_property('communication_status', 1)
            end
        else
            self.read_fail_count = 0
            self:dal_refresh_property('communication_status', 0)
        end
    end
    
    local PS_TRY_CNT = 30 -- 重试次数
    function psu_slot:power_monitor_entry()
        self.refresh_info_nums = 0
        self.read_fail_count = 0
        self:add_monitor_tasks(function()
            while true do
                self:refresh_batch_query_info()
                self.scan_status = self.scan_status | get_pbit(2) | get_pbit(1)
                self:dal_refresh_property('scan_status', self.scan_status)
                self:sleep_time(1000, 1000)
                self.refresh_info_nums = self.refresh_info_nums + 1
                self:update_communication_status()
            end
        end)
        self:add_monitor_tasks(
            function()
                self:time_service_task()
            end
        )
        self:add_monitor_tasks(
            function()
                while true do
                    self.protocol:canbus_recover_to_main_channel()
                    self:sleep_time(30000, 30000)
                end
            end
        )
        self.scan_status = self.scan_status | get_pbit(3)
        self:dal_refresh_property('scan_status', self.scan_status)
        self:get_dynamic_data('rate', PS_TRY_CNT)
    end
    return psu_slot
end