-- 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 log = require 'mc.logging'
local skynet = require 'skynet'
local ctx = require 'mc.context'
local hw_channel= {}

local OK<const> = 0
local ERR<const> = 1

local hw_construction = ""

local function calculate(num1, num2, operator)
    local operators = {
        [1]  = function(a, b) return a < b and OK or ERR end,
        [2]  = function(a, b) return a <= b and OK or ERR end,
        [3]  = function(a, b) return a > b and OK or ERR end,
        [4]  = function(a, b) return a >= b and OK or ERR end,
        [5]  = function(a, b) return a == b and OK or ERR end,
        [6]  = function(a, b) return a ~= b and OK or ERR end,
    }
    return operators[operator](num1, num2)
end

function hw_channel.accessor_input_test(obj)
    if not obj or not obj.Operator or not obj.Input or not obj.InputValue or not obj.InputValue[1] then
        return ERR, "Failed to obtain the object or attribute value."
    end
    hw_construction = string.format("Input: %s, InputValue: %s, Operator: %s",obj.Input, obj.InputValue[1], obj.Operator)
    return calculate(obj.Input, obj.InputValue[1], obj.Operator), hw_construction
end

function hw_channel.accessor_loopback_test(obj)
    if not obj or not obj.Operator or not obj.Input or not obj.InputValue or not obj.OutputValue then
        return ERR, "Failed to obtain the object or attribute value."
    end
    if #obj.InputValue ~= #obj.OutputValue and #obj.OutputValue > 0 then
        return ERR, "The InputValue and OutputValue lengths do not match."
    end
    for i = 1, #obj.OutputValue do
        obj.Output = obj.OutputValue[i]
        skynet.sleep(10)
        if calculate(obj.Input, obj.InputValue[i], obj.Operator) == ERR then
            hw_construction = string.format("Input: %s, InputValue[%s]: %s, Operator: %s",obj.Input, i, obj.InputValue[i], obj.Operator)
            return ERR, hw_construction
        end
    end
    return OK, ""
end

function hw_channel.chip_input_test(obj)
    return OK, ""
end
local function string_to_hex(str)
    local hex_str = ''
    for i = 1, #str do
        local byte = string.byte(str, i)
        hex_str = hex_str.."0x"..string.format("%02X",byte)..","
    end
    return hex_str
end
-- output写入  input读出
function hw_channel.chip_loopback_test(obj)
    if not obj or not obj.Operator or not obj.InputChip or not obj.InputSize or not obj.InputOffset or
        not obj.InputMask or not obj.OutputChip or not obj.OutputSize or not obj.OutputOffset or
        not obj.InputValue or not obj.OutputValue then
        return ERR, "Failed to obtain the object or attribute value"
    end
    local outputChip = obj.OutputChip
    local realOutputValue = '';
    -- 写入数据拼接
    for i = 1, #obj.OutputValue do
        log:notice('[chip_loopback_test] chip write obj.OutputValue[%s]: %s', i, obj.OutputValue[i])
        realOutputValue = realOutputValue .. string.char(obj.OutputValue[i])
    end
    log:notice('[chip_loopback_test] realOutputValue: %s', string_to_hex(realOutputValue))
    local ok, err = pcall(function()
        return outputChip:Write(ctx.new(), obj.OutputOffset, realOutputValue)
    end)
    if not ok then
        log:error('[chip_loopback_test] chip write error: %s', err)
        return ERR, err
    end
    -- SleepTime默认100ms
    skynet.sleep(obj.SleepTime)
    log:info('sleepTime= %dms',obj.SleepTime*10)
    -- 读取Chip
    local inputChip = obj.InputChip
    local ok, ret = pcall(function()
        return inputChip:Read(ctx.new(), obj.InputOffset, obj.InputSize)
    end)
    if not ok then
        log:error('[chip_loopback_test] chip read error: %s', ret)
        return ERR, ret
    end
    log:notice('[chip_loopback_test] chip read ret: %s', string_to_hex(ret))
    -- Chip读取值与掩码相与后，同预期值对比
    local retArray = { string.byte(ret, 1, -1) }
    for i = 1, #obj.InputMask do
        log:notice(
            '[chip_loopback_test] chip read:i= %s, retArray[i]= %s, InputMask[i]= %s, InputValue[i]=%s',
            i, retArray[i], obj.InputMask[i], obj.InputValue[i])
        if calculate(retArray[i] & obj.InputMask[i], obj.InputValue[i], obj.Operator) == ERR then
            hw_construction = string.format("i= %s, retArray[i]= %s, InputMask[i]= %s, InputValue[i]=%s",
            i, retArray[i], obj.InputMask[i], obj.InputValue[i])
            return ERR, hw_construction
        end
    end
    log:info('[chip_loopback_test] OK')
    return OK, ""
end

function hw_channel.can_loopback_test(obj)
    return OK, ""
end

-- 功能函数二维数组[IFType][TestType]
hw_channel.funcs = {
    {hw_channel.accessor_input_test, nil, hw_channel.accessor_loopback_test},
    {hw_channel.chip_input_test, nil, hw_channel.chip_loopback_test},
    {nil, nil, hw_channel.can_loopback_test}
}

return hw_channel