-- 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: 网卡模块debug命令
local log                          = require 'mc.logging'
local class                        = require 'mc.class'
local singleton                    = require 'mc.singleton'
local c_network_port               = require 'device.class.network_port'
local c_network_adapter            = require 'device.class.network_adapter'
local cmd_handler                  = require 'debug.cmd_handler'
local MCTP_MSG_HEAD_LEN <const>    = 16
local MCTP_MAX_PAYLOAD_LEN <const> = 256
local MCTP_MAX_PACKET_SIZE <const> = MCTP_MSG_HEAD_LEN + MCTP_MAX_PAYLOAD_LEN
local debug                        = class()

local function hex_to_bin(hex_str)
    local bin_data = ''
    local hex_byte, bin_byte
    for i = 1, #hex_str, 2 do
        hex_byte = string.sub(hex_str, i, i + 1)
        bin_byte = string.char(tonumber(hex_byte, 16))
        bin_data = bin_data .. bin_byte
    end
    return bin_data
end

local function get_byte(data, i)
    return string.byte(data, i) or 0
end

local function parse_data(data)
    local str = '\\nresponse as fllows:\\n'
    for i = 1, MCTP_MAX_PACKET_SIZE, 16 do
        str = str .. string.format(string.rep("%02x", 16, " "),
            get_byte(data, i), get_byte(data, i + 1), get_byte(data, i + 2), get_byte(data, i + 3),
            get_byte(data, i + 4), get_byte(data, i + 5), get_byte(data, i + 6), get_byte(data, i + 7),
            get_byte(data, i + 8), get_byte(data, i + 9), get_byte(data, i + 10), get_byte(data, i + 11),
            get_byte(data, i + 12), get_byte(data, i + 13), get_byte(data, i + 14), get_byte(data, i + 15)) .. '\\n'
    end
    return str
end

function debug:send_and_receive_ncsi(node_id, command_code, payload)
    local port = c_network_port.collection:find({ NodeId = node_id })
    if not port then
        log:error('invalid node_id:%s', node_id)
        return 'invalid node_id'
    end
    local card = c_network_adapter.collection:find({ ID = port.NetworkAdapterId })
    if not card or not card.SupportedMctp then
        return 'card not support mctp'
    end

    local hex_str = string.gsub(payload, "-", "")
    local bin_data = hex_to_bin(hex_str)

    if not cmd_handler or not cmd_handler.handlers or not cmd_handler.handlers[command_code] then
        local resp_data = port:send_cmd(command_code, bin_data)
        if not resp_data then
            return 'mctp not start'
        end
        return parse_data(resp_data)
    end
    local handler = cmd_handler.handlers[command_code]
    -- 当前仅支持CX5系列和Hi182x系列的NCSI标准协议命令
    if command_code == 0x15 then
        return handler(card)
    elseif command_code == 0x0A then
        return handler(port)
    end
end

return singleton(debug)