-- 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: test the external IPMI sensor interfaces of sensor.
local log = require 'mc.logging'
local bs = require 'mc.bitstring'
local ipmi = require 'sensor.ipmi.ipmi'
local common = require 'test_sensor_common'

local ipmi_interface = {}
ipmi_interface.__index = ipmi_interface

function ipmi_interface.test_set_sensor_hysteresis(bus)
    log:info('== Testing set sensor hysteresis ...')

    -- ipmi command: 'ipmitool raw 0x04 0x24 <number> 0x00 <pos> <neg>'
    local netfn = 0x04
    local cmd = 0x24

    -- 门限传感器设置迟滞量
    local req = ipmi.SetSensorHysteresis.req.new(1, 0, 2, 2)
    local payload = bs.new(ipmi.SetSensorHysteresis.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok, 'error: ' .. tostring(rsp))
    local rsp = bs.new(ipmi.SetSensorHysteresis.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)

    -- 离散传感器设置迟滞量
    req = ipmi.SetSensorHysteresis.req.new(2, 0, 0, 0)
    payload = bs.new(ipmi.SetSensorHysteresis.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok, 'error: ' .. tostring(rsp))
    rsp = bs.new(ipmi.SetSensorHysteresis.encode):unpack(ret)
    assert(rsp.CompletionCode ~= 0x00, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_get_sensor_hysteresis(bus)
    log:info('== Testing get sensor hysteresis ...')

    -- ipmi command: 'ipmitool raw 0x04 0x25 <number> 0x00'
    local netfn = 0x04
    local cmd = 0x25

    -- 门限传感器查询迟滞量
    local req = ipmi.GetSensorHysteresis.req.new(1, 0)
    local payload = bs.new(ipmi.GetSensorHysteresis.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok, 'error: ' .. tostring(rsp))
    local rsp = bs.new(ipmi.GetSensorHysteresis.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.PHysteresis == 2, 'actual: ' .. rsp.PHysteresis)
    assert(rsp.NHysteresis == 2, 'actual: ' .. rsp.NHysteresis)

    -- 离散传感器查询迟滞量
    req = ipmi.GetSensorHysteresis.req.new(2, 0)
    payload = bs.new(ipmi.GetSensorHysteresis.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok, 'error: ' .. tostring(rsp))
    rsp.CompletionCode = ret:byte(1)
    assert(rsp.CompletionCode ~= 0x00, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_set_sensor_threshold(bus)
    log:info('== Testing set sensor threshold ...')

    -- ipmi command: 'ipmitool raw 0x04 0x26 <number> 0x00 <flags> <thresholds>'
    -- flags: LNCFlag, LCRFlag, LNRFlag, UNCFlag, UCRFlag, UNRFlag
    -- thresholds: LNCValue, LCRValue, LNRValue, UNCValue, UCRValue, UNRValue
    local netfn = 0x04
    local cmd = 0x26

    -- 门限传感器设置门限：上限严重 60；上限一般：50
    local req = ipmi.SetSensorThreshold.req.new(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 50, 60, 0)
    local payload = bs.new(ipmi.SetSensorThreshold.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.SetSensorThreshold.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    -- 上紧急门限Flag为0，传入也不报错
    req = ipmi.SetSensorThreshold.req.new(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 50, 60, 70)
    payload = bs.new(ipmi.SetSensorThreshold.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp.CompletionCode = ret:byte(1)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    -- 上紧急门限Flag为1，由于不支持修改，传入报错
    req = ipmi.SetSensorThreshold.req.new(1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 50, 60, 70)
    payload = bs.new(ipmi.SetSensorThreshold.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp.CompletionCode = ret:byte(1)
    assert(rsp.CompletionCode ~= 0x00, 'actual: ' .. rsp.CompletionCode)
    -- 离散传感器设置门限：不支持设置
    req = ipmi.SetSensorThreshold.req.new(2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 50, 60, 0)
    payload = bs.new(ipmi.SetSensorThreshold.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp.CompletionCode = ret:byte(1)
    assert(rsp.CompletionCode ~= 0x00, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_get_sensor_threshold(bus)
    log:info('== Testing get sensor threshold ...')

    -- ipmi command: 'ipmitool raw 0x04 0x27 <number> 0x00'
    local netfn = 0x04
    local cmd = 0x27

    -- 门限传感器查询门限
    local req = ipmi.GetSensorThreshold.req.new(1, 0)
    local payload = bs.new(ipmi.GetSensorThreshold.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSensorThreshold.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.UNCFlag == 1, 'actual: ' .. rsp.UNCFlag)
    assert(rsp.UNCValue == 50, 'actual: ' .. rsp.UNCValue)
    assert(rsp.UCRFlag == 1, 'actual: ' .. rsp.UCRFlag)
    assert(rsp.UCRValue == 60, 'actual: ' .. rsp.UCRValue)
    assert(rsp.LNRFlag == 0, 'actual: ' .. rsp.LNRFlag)

    -- 离散型传感器查询门限：不支持查询
    req = ipmi.GetSensorThreshold.req.new(2, 0)
    payload = bs.new(ipmi.GetSensorThreshold.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp.CompletionCode = ret:byte(1)
    assert(rsp.CompletionCode ~= 0x00, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_set_sensor_event_enable(bus)
    log:info('== Testing set sensor event enable ...')

    -- ipmi command: 'ipmitool raw 0x04 0x28 <number> <status> <assert_mask> <deassert_mask>'
    local netfn = 0x04
    local cmd = 0x28

    -- 门限传感器设置使能
    local sc = string.char
    local datas = {sc(1), sc(3), sc(0x72), sc(0x72), sc(0x72), sc(0x72)}
    local req = ipmi.SetSensorEventEnable.req.new(table.concat(datas, ''))
    local payload = bs.new(ipmi.SetSensorEventEnable.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.SetSensorEventEnable.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    -- 传感器下number异常，预期报错
    datas = {sc(99), sc(3), sc(0x72), sc(0x72), sc(0x72), sc(0x72)}
    req = ipmi.SetSensorEventEnable.req.new(table.concat(datas, ''))
    payload = bs.new(ipmi.SetSensorEventEnable.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    rsp = bs.new(ipmi.SetSensorEventEnable.encode):unpack(ret)
    assert(ok)
    assert(rsp.CompletionCode ~= 0x00, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_get_sensor_event_enable(bus)
    log:info('== Testing get sensor event enable ...')

    -- ipmi command: 'ipmitool raw 0x04 0x29 <number>'
    local netfn = 0x04
    local cmd = 0x29

    -- 门限传感器查询使能
    local req = ipmi.GetSensorEventEnable.req.new(1)
    local payload = bs.new(ipmi.GetSensorEventEnable.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSensorEventEnable.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.AssertMask == 0x0280, 'actual: ' .. rsp.AssertMask)
    assert(rsp.DeassertMask == 0x0280, 'actual: ' .. rsp.DeassertMask)

    -- 离散传感器查询使能
    req = ipmi.GetSensorEventEnable.req.new(2)
    payload = bs.new(ipmi.GetSensorThreshold.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.GetSensorEventEnable.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.AssertMask == 0x0034, 'actual: ' .. rsp.AssertMask)
    assert(rsp.DeassertMask == 0x0020, 'actual: ' .. rsp.DeassertMask)
end

function ipmi_interface.test_get_sensor_event_status(bus)
    log:info('== Testing get sensor event status ...')

    -- ipmi command: 'ipmitool raw 0x04 0x2B <number>'
    local netfn = 0x04
    local cmd = 0x2B

    -- 获取门限传感器的状态
    local req = ipmi.GetSensorEventStatus.req.new(1)
    local payload = bs.new(ipmi.GetSensorEventStatus.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSensorEventStatus.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.AssertStatusL)
    assert(rsp.DeassertStatusL)

    -- 获取离散传感器的状态
    req = ipmi.GetSensorEventStatus.req.new(2)
    payload = bs.new(ipmi.GetSensorEventStatus.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.GetSensorEventStatus.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.AssertStatusL)
    assert(rsp.DeassertStatusL)
end

function ipmi_interface.test_get_sensor_reading(bus)
    log:info('== Testing get sensor reading ...')

    -- ipmi command: 'ipmitool raw 0x04 0x2D <number>'
    local netfn = 0x04
    local cmd = 0x2D

    -- 门限传感器获取读数
    local req = ipmi.GetSensorReading.req.new(1)
    local payload = bs.new(ipmi.GetSensorReading.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSensorReading.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.Reading == 35, 'actual: ' .. rsp.Reading)
    assert(rsp.AssertStatus == 0x00C0, 'actual: ' .. rsp.AssertStatus)

    -- 离散传感器获取读数
    req = ipmi.GetSensorReading.req.new(2)
    payload = bs.new(ipmi.GetSensorReading.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.GetSensorReading.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.Reading == 0, 'actual: ' .. rsp.Reading)
    assert(rsp.AssertStatus == 0x8000, 'actual: ' .. rsp.AssertStatus)
end

function ipmi_interface.test_get_sensor_type(bus)
    log:info('== Testing get sensor type ...')

    -- ipmi command: 'ipmitool raw 0x04 0x2F <number>'
    local netfn = 0x04
    local cmd = 0x2F

    -- 门限传感器获取类型
    local req = ipmi.GetSensorType.req.new(1)
    local payload = bs.new(ipmi.GetSensorType.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSensorType.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.Type == 0x01, 'actual: ' .. rsp.Type)
    assert(rsp.TypeCode == 0x01, 'actual: ' .. rsp.TypeCode)

    -- 离散传感器获取类型
    req = ipmi.GetSensorType.req.new(2)
    payload = bs.new(ipmi.GetSensorType.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.GetSensorType.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.Type == 0x10, 'actual: ' .. rsp.Type)
    assert(rsp.TypeCode == 0x6F, 'actual: ' .. rsp.TypeCode)
end

function ipmi_interface.test_rearm_sensor_event(bus)
    log:info('== Testing rearm sensor event ...')

    -- ipmi command: 'ipmitool raw 0x04 0x2A <number> <rearm> <assert> <deassert>'
    local netfn = 0x04
    local cmd = 0x2A

    -- 连续传感器类型
    local req = ipmi.RearmSensorEvent.req.new(1, 0, 0, 0, 0)
    local payload = bs.new(ipmi.RearmSensorEvent.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.RearmSensorEvent.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)

    -- 离散传感器类型
    req = ipmi.RearmSensorEvent.req.new(2, 0, 1, 36, 32)
    payload = bs.new(ipmi.RearmSensorEvent.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.RearmSensorEvent.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_get_sensor_factors(bus)
    log:info('== Testing get sensor factors ...')

    -- ipmi command: 'ipmitool raw 0x04 0x23 <number> <reading>'
    local netfn = 0x04
    local cmd = 0x23

    -- 连续传感器类型
    local req = ipmi.GetSensorFactors.req.new(1, 0)
    local payload = bs.new(ipmi.GetSensorFactors.decode):pack(req)
    local ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    local rsp = bs.new(ipmi.GetSensorFactors.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.M == 0x64, 'actual: ' .. rsp.M)
    assert(rsp.MT == 0x00, 'actual: ' .. rsp.MT)
    assert(rsp.B == 0x00, 'actual: ' .. rsp.B)
    assert(rsp.BA == 0x00, 'actual: ' .. rsp.BA)
    assert(rsp.Accuracy == 0x00, 'actual: ' .. rsp.Accuracy)
    assert(rsp.RBExp == 224, 'actual: ' .. rsp.RBExp)

    -- 验证功耗传感器
    req = ipmi.GetSensorFactors.req.new(6, 0)
    payload = bs.new(ipmi.GetSensorFactors.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp = bs.new(ipmi.GetSensorFactors.encode):unpack(ret)
    assert(rsp.CompletionCode == 0x00, 'actual: ' .. rsp.CompletionCode)
    assert(rsp.M == 1, 'actual: ' .. rsp.M)
    assert(rsp.B == 166, 'actual: ' .. rsp.B)
    assert(rsp.MT == 0, 'actual: ' .. rsp.MT)
    assert(rsp.BA == 0, 'actual: ' .. rsp.BA)

    -- 离散传感器类型
    req = ipmi.GetSensorFactors.req.new(2, 0)
    payload = bs.new(ipmi.GetSensorFactors.decode):pack(req)
    ok, ret = common.call_ipmi(bus, netfn, cmd, payload)
    assert(ok)
    rsp.CompletionCode = ret:byte(1)
    assert(rsp.CompletionCode == 0xCE, 'actual: ' .. rsp.CompletionCode)
end

function ipmi_interface.test_entry(bus)
    log:info('================ test sensor ipmi interface start ================')

    ipmi_interface.test_set_sensor_hysteresis(bus)
    ipmi_interface.test_get_sensor_hysteresis(bus)
    ipmi_interface.test_set_sensor_threshold(bus)
    ipmi_interface.test_get_sensor_threshold(bus)
    ipmi_interface.test_set_sensor_event_enable(bus)
    ipmi_interface.test_get_sensor_event_enable(bus)
    ipmi_interface.test_get_sensor_event_status(bus)
    ipmi_interface.test_get_sensor_reading(bus)
    ipmi_interface.test_get_sensor_type(bus)
    ipmi_interface.test_rearm_sensor_event(bus)
    ipmi_interface.test_get_sensor_factors(bus)

    log:info('================ test sensor ipmi interface complete ================')
end

return ipmi_interface