-- 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 class = require 'mc.class'
local singleton = require 'mc.singleton'
local bs = require 'mc.bitstring'
local component_communicate = require 'domain.transport.component_communicate'
local bios_enum = require 'domain.bios_firmware.defs'

local ComponentInfoQuery = class(component_communicate)

local IMU_UPLOAD_FILE_CMD = 0x27
-- 1代表获取ComponentVersion.json文件
local GET_CONTENT = 1
-- 0代表获取json文件相关信息：文件总长度、CRC32、版本号
local GET_EXTRAINFO = 0

function ComponentInfoQuery:check_support(type)
    for _, v in pairs(bios_enum.ReadImuFileType) do
        if v == type then
            return
        end
    end
    error(string.format("[bios]get component info failed, type(%s) invalid", type))
end

-- 管理版本
-- 1、固件版本信息管理
-- 2、固件版本存储的文件管理
-- 查询校验信息
function ComponentInfoQuery:get_verification_info(type, system_id)
    self:check_support(type)
    local msg = {
        Header = {
            DestNetFn = self.defs.netfn.OemReqNetfn,
            Cmd = self.defs.cmd.ImuCmd
        },
        Data = {
            SubCmd = IMU_UPLOAD_FILE_CMD,
            FileSelector = type,
            Flag = GET_EXTRAINFO,
            Offset = 0x00
        },
        SendFormat = [[<<0xDB0700:3/unit:8, SubCmd, FileSelector, Flag, Offset:4/unit:8>>]],
        ReceiveFormat = [[<<ManuId:3/unit:8, LastFrame, DataLen, VerifyInfo/string>>]],
        SystemId = system_id
    }
    local ok, res = pcall(function()
        return self.imu_cmd:send_and_receive(msg)
    end)
    if not ok then
        error(string.format("[bios]get_verification_info failed, err:%s", res))
    end
    local verify_format = [[<<FileLen:4/unit:8, Crc32:4/unit:8, Version/string>>]]
    return bs.new(verify_format):unpack(res.VerifyInfo)
end

function ComponentInfoQuery:get_info(type, system_id)
    self:check_support(type)
    local msg = {
        Header = {
            DestNetFn = self.defs.netfn.OemReqNetfn,
            Cmd = self.defs.cmd.ImuCmd
        },
        Data = {
            SubCmd = IMU_UPLOAD_FILE_CMD,
            FileSelector = type,
            Flag = GET_CONTENT,
            Offset = 0x00
        },
        SendFormat = [[<<0xDB0700:3/unit:8, SubCmd, FileSelector, Flag, Offset:4/unit:8>>]],
        ReceiveFormat = [[<<ManuId:3/unit:8, LastFrame, DataLen, FileData/string>>]],
        SystemId = system_id
    }
    local offset = 0
    local file_data = ''
    while true do
        local ok, res = pcall(function()
            return self.imu_cmd:send_and_receive(msg)
        end)
        if not ok then
            error("[bios]send_and_receive failed")
        end
        if res.DataLen == 0 then
            break
        end
        file_data = file_data .. res.FileData
        if res.LastFrame == 0 then
            break
        end
        offset = offset + res.DataLen
        msg.Data.Offset = offset
    end
    return file_data
end

return singleton(ComponentInfoQuery)