-- 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 log = require 'mc.logging'
local lu = require 'luaunit'
local bs = require 'mc.bitstring'
local json = require 'cjson'
local ctx = require 'mc.context'
local ipmi = require 'ipmi'
local enums = require 'ipmi.enums'

local channel_type = enums.ChannelType

local cc = ipmi.types.Cc
local PKG_IPMI = bs.new('<<_,_:2,DestNetFn:6,_:3/unit:8,Cmd,Payload/string>>')
-- 封装ipmi发送函数
local function ipmi_send_msg(bus, netfn, cmd, str)
    local ipmi_req = {
        DestNetFn = netfn,
        Cmd = cmd,
        Payload = str .. "\x00" -- 必须添加最后一位校验
    }
    local req = PKG_IPMI:pack(ipmi_req)
    local ctx_ipmi = json.encode({ChanType = channel_type.CT_LAN:value(), Instance = 1})
    local ok, rsp = pcall(bus.call, bus, 'bmc.kepler.ipmi_core', '/bmc/kepler/IpmiCore',
        'bmc.kepler.IpmiCore', 'Route', 'a{ss}ayay', ctx.get_context_or_default(), req, ctx_ipmi)
    return ok, rsp
end

local test_ipmi = {}

local function test_report_trusted_module_info(bus, netfn, cmd)
    log:notice('============== test_report_trusted_module_info ===========')
    local data = '\xdb\x07\x00\x50\x04\x54\x50\x43\x4d\x07\x31\x2e\x32\x2e\x31\x2e\x33\x07\x31\x2e\x32\x2e\x31\x2e\x33\x01\x07\x31\x2e\x32\x2e\x31\x2e\x33'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.Success)
end

local function test_get_security_module_info(bus)
    log:notice('============== test_get_security_module_info ===========')
    local data = '\xdb\x07\x00\x62'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x92, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(4), 0)
end

local function test_get_gpu_chip_info(bus)
    log:notice('============== test_get_gpu_chip_info ===========')
    local data = '\xdb\x07\x00\x40\x40\x05\x01\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x93, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.ParmOutOfRange)
end

local function test_get_cpld_device_id_info(bus)
    log:notice('============== test_get_cpld_device_id_info ===========')
    local data = '\xdb\x07\x00\x64\x33\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)
end

local GET_CPU_MODULE_POWER_RSP = "<<CompletionCode, ManufactureId:3/unit:8, Power:4/unit:8>>"
local function test_get_cpu_module_power(bus)
    log:notice('============== test_get_cpu_module_power ===========')
    local data = '\xdb\x07\x00\x11\x08\x01'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x93, data)
    lu.assertTrue(ok, rsp)
    local rsp_data = bs.new(GET_CPU_MODULE_POWER_RSP):unpack(rsp)
    lu.assertEquals(rsp_data.CompletionCode, cc.Success)
    lu.assertEquals(rsp_data.ManufactureId, 0x0007DB)
    lu.assertEquals(rsp_data.Power, 160)    -- bcu.sr中配置的为160
end

local GET_FOUR_EYE_DIAGRAM = [[<<
    CompletionCode,
    ManufactureId:3/unit:8,
    Bottom:4/unit:8,
    Top:4/unit:8,
    Left:4/unit:8,
    Right:4/unit:8
>>]]

local function test_get_four_eye_diagram(bus)
    log:notice('============== test_get_four_eye_diagram ===========')
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x00\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    local rsp_data = bs.new(GET_FOUR_EYE_DIAGRAM):unpack(rsp)
    lu.assertEquals(rsp_data.CompletionCode, cc.Success)
    lu.assertEquals(rsp_data.ManufactureId, 0x0007DB)
    lu.assertEquals(rsp_data.Bottom, 0x64)
    lu.assertEquals(rsp_data.Top, 0x0A)
    lu.assertEquals(rsp_data.Left, 0xFFFFFF9C)
    lu.assertEquals(rsp_data.Right, 0xFFFFFFF6)
    data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x01\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xCC)
end

local function check_chip_id(bus)
    local data = '\xdb\x07\x00\x6b\x01\x00\x01\x00\x00\x00\x00\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function chcek_macro_and_lane_id(bus)
    -- macro_id 不在[0, 6]范围
    local data = '\xdb\x07\x00\x6b\x00\x00\x07\x00\x00\x00\x00\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    local rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
    -- macro_id = 6, lane_id = 2
    data = '\xdb\x07\x00\x6b\x00\x00\x06\x00\x02\x00\x00\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
    -- macro_id 在[0, 4], lane_id不为0
    data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x01\x00\x00\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function check_test_mode(bus)
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x02\x00\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function check_scan_mode(bus)
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x04\xff\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function check_pre_tap(bus)
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x00\x04\x03\xff\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function check_pattern_type(bus)
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x00\xff\x03\x02\x00\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function check_eye_type(bus)
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x00\xff\x03\xff\x03\xff\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function check_path_type(bus)
    local data = '\xdb\x07\x00\x6b\x00\x00\x01\x00\x00\x00\x00\xff\x03\xff\x00\x03\xe8\xfd\x00\x00\x10\x27\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, 0x30, 0x90, data)
    lu.assertTrue(ok, rsp)
    rsp_data = string.unpack('I', rsp)
    lu.assertEquals(rsp_data, 0xC9)
end

local function test_get_four_eye_diagram_check_params(bus)
    check_chip_id(bus)
    chcek_macro_and_lane_id(bus)
    check_test_mode(bus)
    check_scan_mode(bus)
    check_pre_tap(bus)
    check_pattern_type(bus)
    check_eye_type(bus)
    check_path_type(bus)
end

function test_ipmi.test_ipmi_cmd(bus)
    test_report_trusted_module_info(bus, 0x30, 0x92)
    test_get_security_module_info(bus)
    test_get_gpu_chip_info(bus)
    test_get_cpld_device_id_info(bus)
    test_get_cpu_module_power(bus)
    test_get_four_eye_diagram(bus)
    test_get_four_eye_diagram_check_params(bus)
end

return test_ipmi
