-- 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: standard ipmi commands
local log = require 'mc.logging'
local bs = require 'mc.bitstring'
local ipmi = require 'sensor.ipmi.ipmi'
local common = require 'test_sensor_common'

local ipmitool = {}
ipmitool.__index = ipmitool

function ipmitool.sel_clear(bus)
    local netfn, cmd, payload
    -- get reserved id
    netfn = 0x0A
    cmd = 0x42
    payload = ''
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSelReserveId.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00)
    local sel_reserve_id = (rsp.ReserveIdH << 8) | rsp.ReserveIdL

    -- clear sel
    cmd = 0x47
    local sb = string.byte
    local rid_l = sel_reserve_id & 0xFF
    local rid_h = (sel_reserve_id >> 8) & 0xFF
    local req = ipmi.ClearSel.req.new(rid_l, rid_h, sb('C'), sb('L'), sb('R'), 0xAA)
    payload = bs.new(ipmi.ClearSel.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.ClearSel.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00)
end

function ipmitool.sel_list(bus)
    local netfn, cmd, payload
    -- get sel info
    netfn = 0x0A
    cmd = 0x40
    payload = ''
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSelInfo.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00)
    if rsp.SelCountH == 0 and rsp.SelCountL == 0 then
        log:info('SEL has no entries')
        return 0, {}
    end

    -- get sel list
    local count = 0
    local sel_lists = {}

    cmd = 0x43
    local cur_id = 0
    local next_id = 0
    while next_id ~= 0xffff do
        cur_id = next_id
        local req = ipmi.GetSelEntry.req.new(0, 0, cur_id & 0xff, (cur_id >> 8) & 0xff, 0, 0xFF)
        payload = bs.new(ipmi.GetSelEntry.decode):pack(req)
        ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
        assert(ok)
        rsp = bs.new(ipmi.GetSelEntry.encode):unpack(ret)
        assert(rsp.CompletionCode == 0x00)
        next_id = (rsp.RecordIdH << 8) | rsp.RecordIdL
        count = count + 1
        table.insert(sel_lists, rsp.Datas)
    end
    return count, sel_lists
end

function ipmitool.add_sel(bus, data, host)
    local netfn, cmd, payload
    netfn = 0x0A
    cmd = 0x44
    local datas = table.concat({string.char(data.data1), string.char(data.data2), string.char(data.data3)}, '')
    local req = ipmi.AddSelEntry.req.new(0, data.sel_type, data.timestamp, data.generate_id, data.msg_version,
        data.sensor_type, data.sensor_no, data.event_type, data.event_dir, datas)
    payload = bs.new(ipmi.AddSelEntry.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload, host)
    assert(ok)
    local rsp = bs.new(ipmi.AddSelEntry.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00)
end

function ipmitool.sdr_list(bus, host)
    local netfn, cmd, payload
    -- get reserved id
    netfn = 0x0A
    cmd = 0x22
    payload = ''
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSelReserveId.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00)
    local sdr_reserve_id_l = rsp.ReserveIdL
    local sdr_reserve_id_h = rsp.ReserveIdH

    -- get sdr list
    local sdr_count = 0
    cmd = 0x23
    local cur_id = 0
    local next_id = 0
    while next_id ~= 0xffff do
        cur_id = next_id
        -- 最终主要验证sdr list数量是否符合预期，对内容无校验要求，因此获取sdr header即可(length = 5)
        local req = ipmi.GetSDR.req.new(sdr_reserve_id_l, sdr_reserve_id_h, cur_id & 0xff, (cur_id >> 8) & 0xff, 0, 5)
        payload = bs.new(ipmi.GetSDR.decode):pack(req)
        ok, ret = common.call_ipmi(bus, netfn, cmd, payload, host)
        assert(ok)
        rsp = bs.new(ipmi.GetSDR.encode):unpack(ret)
        assert(rsp.CompletionCode == 0x00)
        next_id = (rsp.RecordIdH << 8) | rsp.RecordIdL
        sdr_count = sdr_count + 1
    end

    return sdr_count
end

return ipmitool