-- 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.
--         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 log = require 'mc.logging'

local function get_retimer_prop(protocol, args)
    local ok, msg = protocol:retimer_read(args)
    if not ok then
        log:error('fail to read retimer, error: %s', msg)
        return false
    end
    log:debug("get fw_ver: %s", msg)
    return true, msg
end

local function get_retimer_temp(protocol, args)
    -- 基于M88TR51632的SDK手册，获取温度需要先依次给ctl_reg地址写入0,4,5，然后执行retimer_loop_read循环，直到标志位为1
    local terms = {0, 4, 5}
    for _, term in ipairs(terms) do
        local ok, _ = protocol:retimer_write({addr = args.ctl_reg, data = term, use_pec = args.use_pec})
        if not ok then
            log:error('fail to read retimer temperature, fail to write ctl_reg')
            return false, nil
        end
    end
    local args = {addr = args.sts_reg, use_pec = args.use_pec}
    -- 参考SDK手册，直到第16位为1，即读温度成功
    local ok, msg = protocol:retimer_loop_read(args, function(msg)
        return ((msg >> 16) & 0x1) == 1
    end)
    if not ok then
        log:error('fail to read retimer temperature, retimer_loop_read fail: %s', msg)
        return false, nil
    end
    ok, msg = protocol:retimer_read(args)
    if not ok then
        log:error('fail to read retimer temperature, final retimer read fail: %s', msg)
        return false, nil
    end    
    -- 参考SDK手册，根据第12位标志位判断温度是否取反
    local flag = (msg >> 12) & 0x1
    local odr = msg & 0xfff
    if flag == 1 then
        return  true, -odr // 16
    end
    return true, odr // 16
end

local function get_retimer_max_temp(protocol, args)
    -- side 0
    local ok0, temp_0 = get_retimer_temp(protocol, args['0'])
    -- side 1
    local ok1, temp_1 = get_retimer_temp(protocol, args['1'])
    if not ok0 and not ok1 then
        log:error('Side 0 or Side 1 temperature read fail')
        return false, nil
    end

    temp_0 = temp_0 and temp_0 or 0
    temp_1 = temp_1 and temp_1 or 0
    log:debug('side 0 temp: %s, side 1 temp: %s', temp_0, temp_1)
    return true, {temp_0 = temp_0, temp_1 = temp_1}
end

local function parse_version(msg)
    local str = string.format("%08X", msg)
    return string.format("%s.%s.%s.%s", str:sub(1, 2), str:sub(3, 4), str:sub(5, 6), str:sub(7, 8))
end

local function parse_temperature(msg)
    return (msg.temp_0 > msg.temp_1) and msg.temp_0 or msg.temp_1
end

-- retimer的动态属性，需要轮询获取
local PARAMETERS_DYNAMIC<const> = {
    ['TemperatureCelsius'] = {
        fun = get_retimer_max_temp,
        args = {
            ['0'] = {ctl_reg = 0xa10, sts_reg = 0xa18, use_pec = true},
            ['1'] = {ctl_reg = 0xb10, sts_reg = 0xb18, use_pec = true}
        },
        callback = parse_temperature
    }
}

-- retimer的固有属性，仅需上电后获取一次
local PARAMETERS_INHERENT<const> = {
    ['FirmwareVersion'] = {
        fun = get_retimer_prop,
        args = {addr = 0x104c, use_pec = true},
        callback = parse_version
    },
}

return {
    PARAMETERS_DYNAMIC = PARAMETERS_DYNAMIC,
    PARAMETERS_INHERENT = PARAMETERS_INHERENT,
    DEFAULT_VALUE = {
        ['TemperatureCelsius'] = 0
    },
    FAILURE_VALUE = {
        ['TemperatureCelsius'] = 0,
        ['FirmwareVersion'] = "N/A"
    }
}