-- 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 bs = require 'mc.bitstring'
local log = require 'mc.logging'
local skynet = require 'skynet'
local core = require 'network.core'
local ncsi_protocol_intf = require 'ncsi_protocol_intf'
local ncsi_utils = require 'ncsi.ncsi_protocol.ncsi_utils'
local ncsi_def = require 'ncsi.ncsi_protocol.ncsi_def'
local ncsi_packet = require 'ncsi.ncsi_protocol.ncsi_packet'
local ncsi_oem_response = require 'ncsi.ncsi_protocol.ncsi_oem_response'

local ncsi_oem_log = {}

-- 命令类型常量定义
local OEM_COMMAND = 0x50
local OEM_COMMAND_RSP = 0xD0

-- 子命令ID
local GET_LOG_CMD_ID = 0x00
local GET_LOG_SUB_CMD = 0x15
local GET_LOG_SUB_CMD_NEW = 0x16

-- 命令ID
local GET_LOG_SUB_CMD_NEW_LEN = 20

-- 厂商ID
local MANUFACTURE_ID_HUAWEI = 0x000007DB

-- 最大有效载荷长度
local OEM_PAYLOAD_MAX_LEN = 64
local GET_LOG_SUB_CMD_LEN = 16
local SDI_NCSI_CMD_READ_BLOCK = 1024
local ETH_NAME_PREFIX = 'eth'
local MAX_ETH_NUM = 16
local LOG_TYPE_BLACKBOX = 3
local MAX_SUB_LOG = 255
local MAX_BUFFER_LEN = 64 * 1024

-- 帧类型
local CONTROL_FRAME = 0x5a5a5a5a

local g_log_file_name = ''
local g_blackbox_file_name = ''
local g_frame_index = 0

-- 日志上下文结构
local g_log_context = {
    total_length = 0,
    sub_log_num = 0,
    is_control_frame = 0,
    sub_log_lens = {},
    last_frame = 0,
    data_buffer = string.rep('\0', MAX_BUFFER_LEN),
    data_buffer_content_size = 0,
    cur_len = 0,
    sub_cur_len = 0,
    sub_log_idx = 255
}

-- 日志文件类型定义
local g_log_files = {
    {type = 0, name = "type0"},
    {type = 1, name = "type1"},
    {type = 2, name = "type2"},
    {type = 3, name = "type3"}
}

-- 请求和响应的位域结构定义
local get_log_req_bs = bs.new([[<<
    offset:32,
    length:32,
    check_sum:32
>>]])

local get_log_new_req_bs = bs.new([[<<
    frame_type:32,
    offset:32,
    length:32,
    check_sum:32
>>]])

-- 日志响应结构定义
local get_log_over_ncsi_rsp_bs = bs.new([[<<
    rsp_code:16,
    reason_code:16,
    manufacture_id:32,
    cmd_rev:8,
    cmd_id:8,
    sub_cmd:8,
    reserved:8,
    data:1024/string,
    check_sum:32
>>]])

-- 控制帧响应结构
local get_log_over_ncsi_rsp_control_bs = bs.new([[<<
    rsp_code:16,
    reason_code:16,
    manufacture_id:32,
    cmd_rev:8,
    cmd_id:8,
    sub_cmd:8,
    reserved:8,
    total_len:32,
    sub_log_num:8,
    reserved1:8,
    data:514/string
>>]])

-- 数据帧响应结构
local get_log_over_ncsi_rsp_data_bs = bs.new([[<<
    rsp_code:16,
    reason_code:16,
    manufacture_id:32,
    cmd_rev:8,
    cmd_id:8,
    sub_cmd:8,
    reserved:8,
    last_frame:8,
    reserved1:3/string,
    data:2056/string
>>]])

-- 请求和响应的位域结构定义
local oem_command_req_bs = bs.new([[<<
    manufacture_id:32,
    cmd_rev:8,
    cmd_id:8,
    sub_cmd:8,
    reserved:8,
    payload:64/string
>>]])

-- 复位标志信息
local function reset_flags()
    g_log_context.total_length = 0
    g_log_context.sub_log_num = 0
    g_log_context.is_control_frame = 0
    g_log_context.sub_log_lens = {}  -- 从1开始
    g_log_context.last_frame = 0
    g_log_context.data_buffer = string.rep('\0', MAX_BUFFER_LEN)
    g_log_context.data_buffer_content_size = 0
    g_log_context.cur_len = 0
    g_log_context.sub_log_idx = 255
    g_log_context.sub_cur_len = 0
end

-- 将数据写入缓存区
local function write_data_buffer(data_len, log_file, log_over_ncsi_rsp_data)
    -- 判断当前缓存是否还能写入数据
    if (MAX_BUFFER_LEN - g_log_context.data_buffer_content_size) < data_len then
        -- 写入文件
        local success, err = log_file:write(g_log_context.data_buffer:sub(1, g_log_context.data_buffer_content_size))
        if not success then
            log:error('write_data_buffer: fwrite fail: %s', err)
            return false
        end
        -- 清空缓存
        g_log_context.data_buffer = string.rep('\0', MAX_BUFFER_LEN)
        g_log_context.data_buffer_content_size = 0
    end

    -- 复制数据到缓存
    local new_data = log_over_ncsi_rsp_data.data:sub(1, data_len)
    g_log_context.data_buffer = g_log_context.data_buffer:sub(1, g_log_context.data_buffer_content_size) .. new_data
    g_log_context.data_buffer_content_size = g_log_context.data_buffer_content_size + data_len
    g_log_context.cur_len = g_log_context.cur_len + data_len
    g_log_context.sub_cur_len = g_log_context.sub_cur_len + data_len
    return true
end

-- 处理最后一帧
local function process_last_frame(log_file)
    if g_log_context.last_frame == 0 then
        return true
    end

    -- 写入剩余数据
    if g_log_context.data_buffer_content_size > 0 then
        local success, err = log_file:write(g_log_context.data_buffer:sub(1, g_log_context.data_buffer_content_size))
        if not success then
            log:error('process_last_frame: fwrite fail: %s', err)
            return false
        end
        g_log_context.data_buffer_content_size = 0
    end

    -- 计算需要补0的长度
    local log_len = g_log_context.sub_log_lens[g_log_context.sub_log_idx + 1] * 1024
    local remain_len = log_len - g_log_context.sub_cur_len
    if remain_len > 0 then
        g_log_context.cur_len = g_log_context.cur_len + remain_len
        local remain_buffer = string.rep('\0', remain_len)
        local success, err = log_file:write(remain_buffer)
        if not success then
            log:error('process_last_frame: fwrite fail: %s', err)
            return false
        end
    end

    g_log_context.sub_cur_len = 0
    return true
end

-- 解析控制帧内容
local function parse_control_frame(rsp_packet)
    local log_over_ncsi_rsp_control = get_log_over_ncsi_rsp_control_bs:unpack(rsp_packet.payload, true)
    if not log_over_ncsi_rsp_control then
        log:error('Failed to unpack log over NCSI control response payload')
        return
    end
    reset_flags()
    g_log_context.total_length = log_over_ncsi_rsp_control.total_len
    g_log_context.sub_log_num = log_over_ncsi_rsp_control.sub_log_num

    -- 解析子日志长度数组
    local data_str = log_over_ncsi_rsp_control.data
    for i = 1, g_log_context.sub_log_num do
        local start_pos = (i - 1) * 2 + 1
        local end_pos = i * 2
        g_log_context.sub_log_lens[i] = string.unpack(">I2", data_str:sub(start_pos, end_pos))   -- 默认大端序
    end
end

-- 解析数据帧内容
local function parse_data_frame(rsp_packet, data_len)
    local log_over_ncsi_rsp_data = get_log_over_ncsi_rsp_data_bs:unpack(rsp_packet.payload, true)
    if not log_over_ncsi_rsp_data then
        log:error('Failed to unpack log over NCSI data response payload')
        return
    end
    g_log_context.last_frame = log_over_ncsi_rsp_data.last_frame

    if g_log_context.sub_log_idx < 0 or g_log_context.sub_log_idx >= MAX_SUB_LOG then
        log:error('parse_data_frame: sub_log_idx invalid, value = %d', g_log_context.sub_log_idx)
        return
    end

    -- 打开日志文件
    local log_file = io.open(g_log_file_name, "a+")
    if not log_file then
        log:error('parse_data_frame: open log file fail')
        return
    end

    -- 写入数据
    local ret = write_data_buffer(data_len, log_file, log_over_ncsi_rsp_data)
    if not ret then
        log:error('parse_data_frame: write_data_buffer fail')
        log_file:close()
        return
    end

    -- 处理最后一帧
    ret = process_last_frame(log_file)
    if not ret then
        log:error('parse_data_frame: process_last_frame fail')
        log_file:close()
        return
    end

    log_file:close()
end

-- 解析新日志数据
local function parse_new_log_data(rsp_packet, data_len)
    if g_log_context.is_control_frame == 1 then
        parse_control_frame(rsp_packet)
    else
        parse_data_frame(rsp_packet, data_len)
    end
end

-- 验证eth_name并获取eth_num
local function validate_eth_name(eth_name)
    if not eth_name then
        log:error('%s : eth_name is nil', 'validate_eth_name')
        return nil
    end

    local ncsi_comm = require 'ncsi.ncsi_comm'
    local is_customed, eth_num = ncsi_comm.get_instance():is_eth_name_custom(eth_name)
    if is_customed then
        return eth_num
    end

    if string.sub(eth_name, 1, #ETH_NAME_PREFIX) == ETH_NAME_PREFIX then
        local eth_num = tonumber(string.match(eth_name, "eth(%d+)"))
        if not eth_num then
            log:error('%s : Failed to parse eth number from eth name[%s]', 'validate_eth_name', eth_name)
            return nil
        end

        -- 检查网卡号是否有效
        if eth_num >= MAX_ETH_NUM then
            log:error('%s : Get eth num[%u] from eth name[%s] is larger than %u',
                'validate_eth_name', eth_num, eth_name, MAX_ETH_NUM)
            return nil
        end

        return eth_num
    else
        log:error('%s : Invalid eth name[%s]', 'validate_eth_name', eth_name)
        return nil
    end
end

local function fill_oem_ncsi_payload(req_packet, sub_cmd, cmd_id, req_len, log_type, padding)
    local payload_data = {
        manufacture_id = core.htonl(MANUFACTURE_ID_HUAWEI),
        cmd_rev = 0,
        cmd_id = cmd_id,
        sub_cmd = sub_cmd,
        reserved = log_type,
        payload = padding
    }
    req_packet.payload = oem_command_req_bs:pack(payload_data)

    -- 计算校验和和CRC32
    local check_sum = ncsi_utils.get_checksum(req_packet, ncsi_def.PACKET_HEAD_LEN + req_len)

    -- 更新checksum到payload
    payload_data.payload =
        string.rep('\0', OEM_PAYLOAD_MAX_LEN - 4) .. string.pack("I4", core.htonl(check_sum))

    -- 返回最终的payload
    return oem_command_req_bs:pack(payload_data)
end

local function write_log_new_req(req_packet, eth_name, log_type, frame_type, offset, length)
    ncsi_utils.ncsi_cmd_common_config(req_packet)
    req_packet.packet_head.payload_len_hi = 0
    req_packet.packet_head.payload_len_lo = GET_LOG_SUB_CMD_NEW_LEN

    local req_len = ((req_packet.packet_head.payload_len_hi << 8) | req_packet.packet_head.payload_len_lo)
    if req_len >= (ncsi_def.PACKET_ALL_LEN - ncsi_def.ETHERNET_HEAD_LEN - ncsi_def.PACKET_HEAD_LEN) then
        log:error('Request length[%u] is too long', req_len)
        return nil
    end

    -- 构建控制帧请求载荷
    local control_payload = get_log_new_req_bs:pack({
        frame_type = frame_type,
        offset = offset,
        length = length,
        check_sum = 0
    })

    local padding = control_payload .. string.rep('\0', OEM_PAYLOAD_MAX_LEN - #control_payload)
    req_packet.payload = fill_oem_ncsi_payload(req_packet, GET_LOG_SUB_CMD_NEW, GET_LOG_CMD_ID,
        req_len, log_type, padding)

    local req_data = ncsi_utils.ncsi_packet_bs:pack(req_packet)
    return ncsi_protocol_intf.send_ncsi_cmd(req_data,
        req_len + ncsi_def.ETHERNET_HEAD_LEN + ncsi_def.PACKET_HEAD_LEN + 4, eth_name)
end

-- 发送控制帧请求
local function write_send_control_req(req_packet, eth_name, log_type)
    write_log_new_req(req_packet, eth_name, log_type, CONTROL_FRAME, 0, 0)
end

-- 发送数据帧请求
local function write_send_frame_req(req_packet, eth_name, log_type)
    write_log_new_req(req_packet, eth_name, log_type, 0, g_log_context.cur_len, SDI_NCSI_CMD_READ_BLOCK)
end

local function write_get_log_sub_req(req_packet, eth_name, frame_index, log_type, base_offset)
    ncsi_utils.ncsi_cmd_common_config(req_packet)
    req_packet.packet_head.payload_len_hi = 0
    req_packet.packet_head.payload_len_lo = GET_LOG_SUB_CMD_LEN

    local req_len = ((req_packet.packet_head.payload_len_hi << 8) | req_packet.packet_head.payload_len_lo)
    if req_len >= (ncsi_def.PACKET_ALL_LEN - ncsi_def.ETHERNET_HEAD_LEN - ncsi_def.PACKET_HEAD_LEN) then
        log:error('Request length[%u] is too long', req_len)
        return nil
    end

    -- 构建get_log请求载荷
    local get_log_payload = get_log_req_bs:pack({
        offset = base_offset + SDI_NCSI_CMD_READ_BLOCK * frame_index,
        length = SDI_NCSI_CMD_READ_BLOCK,
        check_sum = 0
    })

    local padding = get_log_payload .. string.rep('\0', OEM_PAYLOAD_MAX_LEN - #get_log_payload)
    req_packet.payload = fill_oem_ncsi_payload(req_packet, GET_LOG_SUB_CMD, GET_LOG_CMD_ID, req_len, log_type, padding)

    local req_data = ncsi_utils.ncsi_packet_bs:pack(req_packet)
    return ncsi_protocol_intf.send_ncsi_cmd(req_data,
        req_len + ncsi_def.ETHERNET_HEAD_LEN + ncsi_def.PACKET_HEAD_LEN + 4, eth_name)
end

-- 写入日志数据到文件
local function write_log_data_to_file(log_data, is_blackbox)
    local log_file_name = is_blackbox and g_blackbox_file_name or g_log_file_name

    -- 打开文件
    local file = io.open(log_file_name, "a+")
    if not file then
        log:error('write_log_data_to_file: open log file fail')
        return
    end

    -- 写入数据
    local success, err = file:write(log_data)
    if not success then
        log:error('write_log_data_to_file: write data fail: %s', err)
    end

    -- 关闭文件
    file:close()
end

-- 使用新命令字获取网卡日志
local function hw_get_log_rsp_new(rsp_packet, eth_name)
    -- 验证eth_name并获取eth_num
    local eth_num = validate_eth_name(eth_name)
    if not eth_num then
        return
    end

    -- 计算数据长度
    local data_size = (rsp_packet.packet_head.payload_len_hi << 8) | rsp_packet.packet_head.payload_len_lo
    if data_size < 16 then
        log:error('%s : payload size is invalid[%u]', 'hw_get_log_rsp_new', data_size)
        return
    end

    -- 获取数据长度
    data_size = data_size - 16

    -- 解析新日志数据
    parse_new_log_data(rsp_packet, data_size)
end

-- 处理获取日志响应
local function hw_get_log_rsp(rsp_packet, eth_name)
    if not rsp_packet or not rsp_packet.payload then
        log:error('%s : rsp_packet or rsp_packet.payload is nil', 'hw_get_log_rsp')
        return
    end

    local eth_num = validate_eth_name(eth_name)
    if not eth_num then
        return
    end

    -- 解析响应包
    local pget_log_over_ncsi_rsp = get_log_over_ncsi_rsp_bs:unpack(rsp_packet.payload, true)
    if not pget_log_over_ncsi_rsp then
        log:error('Failed to unpack log over NCSI response payload')
        return
    end

    -- 获取日志类型
    local log_type = pget_log_over_ncsi_rsp.reserved
    local is_blackbox = (log_type == LOG_TYPE_BLACKBOX)

    -- 写入日志数据
    write_log_data_to_file(pget_log_over_ncsi_rsp.data, is_blackbox)
end

local function create_get_log_new_callback_table(eth_name)
    return {
        ncsi_oem_response.create_callback_entry(GET_LOG_CMD_ID, GET_LOG_SUB_CMD_NEW,
            function(rsp) return hw_get_log_rsp_new(rsp, eth_name) end)
    }
end

local function create_get_log_callback_table(eth_name)
    return {
        ncsi_oem_response.create_callback_entry(GET_LOG_CMD_ID, GET_LOG_SUB_CMD,
            function(rsp) return hw_get_log_rsp(rsp, eth_name) end)
    }
end

local function write_oem_command_req(req_packet, eth_name, sub_cmd, arg1, arg2)
    if sub_cmd == GET_LOG_SUB_CMD_NEW and arg1 == CONTROL_FRAME then
        return write_send_control_req(req_packet, eth_name, arg2)
    end

    if sub_cmd == GET_LOG_SUB_CMD_NEW and arg1 == 0 then
        return write_send_frame_req(req_packet, eth_name, arg2)
    end

    if sub_cmd == GET_LOG_SUB_CMD then
        return write_get_log_sub_req(req_packet, eth_name, g_frame_index, arg1, arg2)
    end

    log:error('write oem command req: Unknown sub_cmd: %s', tostring(sub_cmd))
    return ncsi_def.NCSI_FAIL
end

local function read_oem_command_rsp(rsp, eth_name, sub_cmd)
    if sub_cmd == GET_LOG_SUB_CMD_NEW then
        local callback_table = create_get_log_new_callback_table(eth_name)
        return ncsi_oem_response.read_oem_command_rsp(rsp, callback_table)
    end

    if sub_cmd == GET_LOG_SUB_CMD then
        local callback_table = create_get_log_callback_table(eth_name)
        return ncsi_oem_response.read_oem_command_rsp(rsp, callback_table)
    end

    -- 默认处理，只检查响应码
    return ncsi_oem_response.read_oem_command_rsp(rsp, nil)
end

local oem_command_table = {
    [OEM_COMMAND] = write_oem_command_req,
    [OEM_COMMAND_RSP] = read_oem_command_rsp
}

local function log_sub_cmd_new(package_id, eth_name, frame_type, log_type)
    local req_packet = ncsi_packet.create_request_packet(package_id, 0, OEM_COMMAND)

    -- 先创建自定义写入命令表
    local custom_cmd_table = ncsi_utils.create_custom_cmd_table(
        oem_command_table, OEM_COMMAND, write_oem_command_req, GET_LOG_SUB_CMD_NEW, frame_type, log_type
    )

    -- 再创建自定义响应处理表
    custom_cmd_table = ncsi_utils.create_custom_rsp_table(
        custom_cmd_table, OEM_COMMAND_RSP, read_oem_command_rsp, eth_name, GET_LOG_SUB_CMD_NEW
    )

    -- 发送请求并重试
    local ret = ncsi_def.NCSI_FAIL
    for _ = 1, 3 do
        ret = ncsi_utils.ncsi_cmd_ctrl(package_id, 0, req_packet, eth_name, custom_cmd_table)
        if ret == ncsi_def.NCSI_SUCCESS then
            break
        end
        skynet.sleep(1)
    end

    if ret ~= ncsi_def.NCSI_SUCCESS then
        log:error('send_control_frame: Send control command failed, ret = %d', ret)
    end
    return ret
end

-- 发送控制帧请求
local function send_control_frame(package_id, eth_name, log_type)
    g_log_context.is_control_frame = 1
    return log_sub_cmd_new(package_id, eth_name, CONTROL_FRAME, log_type)
end

-- 发送数据帧请求
local function send_data_frame(package_id, eth_name, log_type)
    return log_sub_cmd_new(package_id, eth_name, 0, log_type)
end

-- 获取指定type的网卡日志
local function get_specific_type_log_by_ncsi(package_id, eth_name, log_type)
    -- 先发送控制帧获取子日志个数
    local ret = send_control_frame(package_id, eth_name, log_type)
    if ret ~= ncsi_def.NCSI_SUCCESS then
        g_log_context.is_control_frame = 0
        return ret
    end

    -- 控制帧发送完毕后，等待解析响应，获取子日志个数
    skynet.sleep(1)

    -- 发送数据帧
    g_log_context.sub_log_idx = 0
    while g_log_context.sub_log_idx < g_log_context.sub_log_num and
          g_log_context.cur_len < g_log_context.total_length * SDI_NCSI_CMD_READ_BLOCK do
        while true do
            ret = send_data_frame(package_id, eth_name, log_type)
            if ret ~= ncsi_def.NCSI_SUCCESS then
                return ret
            end
            if g_log_context.last_frame == 1 then
                break
            end
        end
        g_log_context.sub_log_idx = g_log_context.sub_log_idx + 1
    end

    return ncsi_def.NCSI_SUCCESS
end

-- 获取日志数据接口
local function get_specific_type_log_by_ncsi_hw(package_id, eth_name, log_type, total_frame, base_offset)
    local req_packet = ncsi_packet.create_request_packet(package_id, 0, OEM_COMMAND)
    g_frame_index = 0

    -- 先创建自定义写入命令表
    local custom_cmd_table = ncsi_utils.create_custom_cmd_table(
        oem_command_table, OEM_COMMAND, write_oem_command_req, GET_LOG_SUB_CMD, log_type, base_offset
    )

    -- 再创建自定义响应处理表
    custom_cmd_table = ncsi_utils.create_custom_rsp_table(
        custom_cmd_table, OEM_COMMAND_RSP, read_oem_command_rsp, eth_name, GET_LOG_SUB_CMD
    )

    -- 循环处理每一帧
    for index = 0, total_frame - 1 do
        g_frame_index = index

        -- 发送请求并重试
        local ret = ncsi_def.NCSI_FAIL
        for _ = 1, 3 do
            ret = ncsi_utils.ncsi_cmd_ctrl(package_id, 0, req_packet, eth_name, custom_cmd_table)
            if ret == ncsi_def.NCSI_SUCCESS then
                break
            end
            skynet.sleep(1)
        end

        if ret ~= ncsi_def.NCSI_SUCCESS then
            log:error('get_specific_type_log_by_ncsi_hw: Send control command failed, ret = %d', ret)
            return ret
        end
    end

    return ncsi_def.NCSI_SUCCESS
end

-- 设置日志文件名
local function set_log_file_name(log_type, log_dir, time)
    local log_types = {
        [0] = "mpu_ucode",
        [1] = "counter",
        [2] = "register",
        [3] = "last_word"
    }
    g_log_file_name = string.format("%s%s_%s.bin", log_dir, log_types[log_type], time)
end

-- 获取网卡日志
function ncsi_oem_log.get_log_by_ncsi_hw(package_id, eth_name, log_dir, time)
    -- 获取mpu ucode日志
    set_log_file_name(0, log_dir, time)
    local ret = get_specific_type_log_by_ncsi_hw(package_id, eth_name, 0, 640, 0)
    if ret ~= ncsi_def.NCSI_SUCCESS then
        log:error('%s : get mpu ucode log failed, ret = %d', 'get_log_by_ncsi_hw', ret)
        return ret
    end

    -- 获取last_word日志
    set_log_file_name(3, log_dir, time)
    ret = get_specific_type_log_by_ncsi_hw(package_id, eth_name, 0, 256, 0xA0000)
    if ret ~= ncsi_def.NCSI_SUCCESS then
        log:error('%s : get last word log failed, ret = %d', 'get_log_by_ncsi_hw', ret)
        return ret
    end

    -- 获取counter日志
    set_log_file_name(1, log_dir, time)
    ret = get_specific_type_log_by_ncsi_hw(package_id, eth_name, 1, 136, 0)
    if ret ~= ncsi_def.NCSI_SUCCESS then
        log:error('%s : get counter log failed, ret = %d', 'get_log_by_ncsi_hw', ret)
        return ret
    end

    -- 获取register日志
    set_log_file_name(2, log_dir, time)
    ret = get_specific_type_log_by_ncsi_hw(package_id, eth_name, 2, 8, 0)
    if ret ~= ncsi_def.NCSI_SUCCESS then
        log:error('%s : get register log failed, ret = %d', 'get_log_by_ncsi_hw', ret)
        return ret
    end

    return ret
end

-- 获取网卡黑匣子
function ncsi_oem_log.get_blackbox_by_ncsi_hw(package_id, eth_name, log_name)
    -- 设置blackbox日志文件名
    g_blackbox_file_name = log_name

    -- 获取blackbox日志，类型3，60帧，偏移0
    local ret = get_specific_type_log_by_ncsi_hw(package_id, eth_name, 3, 60, 0)
    if ret ~= ncsi_def.NCSI_SUCCESS then
        log:error('%s : get blackbox failed, ret = %d', 'get_blackbox_by_ncsi_hw', ret)
        return ret
    end

    return ret
end

-- 通过0x16命令字收集日志
function ncsi_oem_log.get_log_by_ncsi_hw_new(package_id, eth_name, log_dir, time)
    for _ , log_file in ipairs(g_log_files) do
        log:info('start to collect ncsi log, log type = %u', log_file.type)
        -- 设置日志文件名
        g_log_file_name = string.format("%s%s_%s.bin", log_dir, log_file.name, time)

        -- 获取指定类型的日志
        local ret = get_specific_type_log_by_ncsi(package_id, eth_name, log_file.type)
        if ret ~= ncsi_def.NCSI_SUCCESS then
            log:error('get_log_by_ncsi_hw_cmd16: get log failed, ret = %d, name: %s', ret, log_file.name)
            return ret
        end
    end

    log:info('collect log by ncsi with new command successfully')
    return ncsi_def.NCSI_SUCCESS
end

return ncsi_oem_log
