-- 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 CX5 = require 'hardware_config.CX5'
local libmgmt_protocol = require 'libmgmt_protocol'
local PACKAGE_ID <const> = 0x03
local utils = require 'mc.utils'
local log = require 'mc.logging'

local disable_hardware_arbitration_rsp = bs.new([[<<
    response_code:16/big,
    reason_code:16/big
    >>]])

local optical_get_date_rsp = bs.new([[<<
    reserved:8,
    i2c_addres:8,
    page_number:8,
    dev_address:16,
    page_lock_field:8,
    operation:8,
    transfer_size:16,
    data:16
    >>]])
 local date_req = bs.new([[<<
    i2c_address:8,
    page_number:8,
    dev_address:16,
    page_lock_field:8,
    operation:8,
    transfer_size:16
    >>]])
local optical_data_rsp = bs.new([[<<
    reserved:8,
    i2c_addres:8,
    page_number:8,
    dev_address:16,
    page_lock_field:8,
    operation:8,
    transfer_size:16,
    data:16/big
    >>]])
local optical_get_channel_info_rsp = bs.new([[<<
    reserved:8,
    i2c_addres:8,
    page_number:8,
    dev_address:16,
    page_lock_field:8,
    operation:8,
    transfer_size:16,
    channel1_data:16/big,
    channel2_data:16/big,
    channel3_data:16/big,
    channel4_data:16/big
    >>]])
local optical_get_channel_info_cmis_rsp = bs.new([[<<
    reserved:8,
    i2c_addres:8,
    page_number:8,
    dev_address:16,
    page_lock_field:8,
    operation:8,
    transfer_size:16,
    channel1_data:16/big,
    channel2_data:16/big,
    channel3_data:16/big,
    channel4_data:16/big,
    channel5_data:16/big,
    channel6_data:16/big,
    channel7_data:16/big,
    channel8_data:16/big
    >>]])

local set_host_access_req = bs.new([[<<
    reserved:24,
    host_access_state:8
    >>]])

local host_access_rsp = bs.new([[<<
    reserved_1:8,
    reserved_2:24,
    host_access_state:8
    >>]])

local set_extended_host_privilege_req = bs.new([[<<
    emb_cpu_setting_change:2,
    pcc_fw_update:2,
    nic_fw_update:2,
    nic_reset:2,
    nic_flash_access:2,
    external_host_parameters_change:2,
    network_port_parameters_change:2,
    global_non_volatile_change:2,
    reserved:16
    >>]])

local get_extended_host_privilege_rsp = bs.new([[<<
    reserved_1:8,
    emb_cpu_setting_change:2,
    pcc_fw_update:2,
    nic_fw_update:2,
    nic_reset:2,
    nic_flash_access:2,
    external_host_parameters_change:2,
    network_port_parameters_change:2,
    global_non_volatile_change:2, 
    reserved_2:16
    >>]])

local set_mode_req = bs.new([[<<
    reserved_1:24,
    offload_engine:1,
    reserved_2:7
    >>]])

local get_mode_rsp = bs.new([[<<
    reserved_1:8,
    reserved_2:24,
    offload_engine:1,
    reserved_3:7
    >>]])

local identifier_switch <const> = {
    [0x00] = 'UNDEF',
    [0x01] = 'GBIC',
    [0x03] = 'SFP_SFP_PLUS_SFP28',
    [0x0c] = 'QSFP',
    [0x0d] = 'QSFP_PLUS',
    [0x11] = 'QSFP28',
    [0x1b] = 'DSFP',
    [0x1e] = 'QSFP+ or later with CMIS'
}

local connector_switch <const> = {
    [0x00] = 'UNDEF',
    [0x07] = 'LC',
    [0x0c] = 'MPO',
    [0x0b] = 'OPTICAL_PIGTAIL',
    [0x21] = 'COPPER_PIGTAIL',
    [0x23] = 'NO_SEPARABLE_CONNECTOR'
}

local function trim(s)
    return s:match '^%s*(.*)':match '(.-)%s*$'
end

local BF3 = {
    properties = {
        DisableHardwareArbitration = {
            protocol = 'ncsi_standard',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                packet_type = 0x01,
                expect_rsp_packet_type = 0x81,
                data = '\x00\x00\x00\x01'
            },
            response = function(data)
                return disable_hardware_arbitration_rsp:unpack(data, true)
            end
        },
        Test = {
            protocol = 'ncsi_standard',
            action = 'on_demand',
            request = {package_id = PACKAGE_ID},
            response = function(data) return data end
        },
        OpticalGetIdentifier = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                -- ReqPayload
                -- {
                -- u32 manufacturer_id
                -- u8 cmd_mellanox
                -- u8 mellanox_cmd_id
                -- u8 parameter
                -- u8 reserved
                ----- 从这里开始表示
                -- u8 i2c_address
                -- u8 page_number 0
                -- u16 dev_address
                -- u8 page_lock_field 0
                -- u8 operation 0
                -- u16 transfer_size 0x0100
                -- =======结束==========
                -- u32 checksum
                -- }
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x0,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100
                }, true)
            },

            response = function(data)
                -- RspPayload
                -- {
                -- u16 response_code
                -- u16 reason_code
                -- u32 manufacturer_id
                -- u8 cmd_mellanox
                -- u8 mellanox_cmd_id
                -- u8 parameter
                ---- 从这里开始表示----
                -- u8 reserved
                -- u8 i2c_addres
                -- u8 page_number
                -- u16 dev_address 
                -- u8  page_lock_field 0
                -- u8 operation 0
                -- u16 transfer size 0x0100
                -- u32*12 dword
                -- =======结束==========
                -- u32 checksum
                -- }
                local r = optical_get_date_rsp:unpack(data, true)
                -- 协商的光模块协议版本
                -- 1E 或1B：CMIS
                -- 其他 SFF-8636
                if not r then 
                    return 'OpticalTempSFF8636' 
                end
                local identifier = r.data & 0xff
                local IDENTIFIER_CMIS<const> = 0x1e
                local SFF8024_ID_DSFP<const> = 0x1b
 
                if identifier == IDENTIFIER_CMIS or identifier ==
                    SFF8024_ID_DSFP then
                    return 'OpticalTempCMIS50'
                end
                return 'OpticalTempSFF8636'
            end
        },
        -- SFF-8636
        -- u8 i2c_addres  0x50
        -- u16 dev_address  0x1600
        OpticalTempSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x1600,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100 -- 取一个字节数据
                }, true)
            },

            response = function(data)
                -- RspPayload
                -- {
                -- u16 response_code
                -- u16 reason_code
                -- u32 manufacturer_id
                -- u8 cmd_mellanox
                -- u8 mellanox_cmd_id
                -- u8 parameter
                ---- 从这里开始表示----
                -- u8 reserved
                -- u8 i2c_addres
                -- u8 page_number
                -- u16 dev_address 
                -- u8 page_lock_field 0
                -- u8 operation 0
                -- u16 transfer_size 0x0100
                -- u32 dword
                -- =======结束==========
                -- u32 checksum
                -- }
                local r = optical_get_date_rsp:unpack(data, true)
                if not r then return nil end
                return r.data & 0xff
            end
        },
        -- CMIS-5.0
        -- 0x50
        -- 0x0e00
        OpticalTempCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x0e00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100 -- 取一个字节数据
                }, true)
            },

            response = function(data)
                -- RspPayload
                -- {
                -- u16 response_code
                -- u16 reason_code
                -- u32 manufacturer_id
                -- u8 cmd_mellanox
                -- u8 mellanox_cmd_id
                -- u8 parameter
                ---- 从这里开始表示----
                -- u8 reserved
                -- u8 i2c_addres
                -- u8 page_number
                -- u16 dev_address 
                -- u8 page_lock_field 0
                -- u8 operation 0
                -- u16 transfer_size 0x0100
                -- u32 dword
                -- =======结束==========
                -- u32 checksum
                -- }
                local r = optical_get_date_rsp:unpack(data, true)
                if not r then return nil end
                return r.data & 0xff
            end
        },
        -- 光模块协议
        OpticalIdentifier = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x0,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100
                }, true)
            },

            response = function(data)
                local r = optical_get_date_rsp:unpack(data, true)
                -- 协商的光模块协议版本
                -- 1E 或1B：CMIS
                -- 其他 SFF-8636
                local identifier = r.data & 0xff
                return identifier_switch[identifier] or ''
            end
        },
        -- 光模块电压(SFF8636)
        OpticalVoltageSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x1a00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0200 -- 取2个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_data_rsp:unpack(data, true)
                if not r then return nil end
                local voltage_base <const> = 0.0001
                return r.data * voltage_base
            end
        },
        -- 光模块偏置电流(SFF8636)
        OpticalBiasSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x2a00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0800 -- 取8个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_channel_info_rsp:unpack(data, true)
                if not r then return nil end
                local bias_base <const> = 0.002
                return {
                    r.channel1_data * bias_base,
                    r.channel2_data * bias_base,
                    r.channel3_data * bias_base,
                    r.channel4_data * bias_base
                }
            end
        },
        -- 光模块输入功率(SFF8636)
        OpticalInputPowerSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x2200,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0800 -- 取8个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_channel_info_rsp:unpack(data, true)
                if not r then return nil end
                local input_power_base <const> = 0.0001
                return {
                    r.channel1_data * input_power_base,
                    r.channel2_data * input_power_base,
                    r.channel3_data * input_power_base,
                    r.channel4_data * input_power_base
                }
            end
        },
        -- 光模块输出功率(SFF8636)
        OpticalOutputPowerSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x3200,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0800 -- 取8个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_channel_info_rsp:unpack(data, true)
                if not r then return nil end
                local output_power_base <const> = 0.0001
                return {
                    r.channel1_data * output_power_base,
                    r.channel2_data * output_power_base,
                    r.channel3_data * output_power_base,
                    r.channel4_data * output_power_base
                }
            end
        },
        -- 光模块厂商、部件编码等信息(SFF8636)
        OpticalStaticInfoSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 60,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x9400,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x4000 -- 取64个字节数据
                }, true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8,
                    i2c_addres:8,
                    page_number:8,
                    dev_address:16,
                    page_lock_field:8,
                    operation:8,
                    transfer_size:16,
                    vendor_name:16/string,
                    extended_module:8,
                    vendor_oui:3/string,
                    vendor_pn:16/string,
                    vendor_rev:2/string,
                    wavelength:16,
                    wavelength_tolerance:16,
                    max_case_temp:8,
                    cc_base:8,
                    ethernet_codes:8,
                    options:24,
                    vendor_sn:16/string
                >>]]):unpack(data, true)
                if not r then return nil end
                return {
                    Manufacturer = trim(r.vendor_name),
                    PartNumber = trim(r.vendor_pn),
                    SerialNumber = trim(r.vendor_sn),
                    RevisionNumber = trim(r.vendor_rev)
                }
            end
        },
        -- 光模块连接器类型(SFF8636)
        OpticalConnectorTypeSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 60,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x8200,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100 -- 取1个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_date_rsp:unpack(data, true)
                if not r then return nil end
                return connector_switch[r.data] or ''
            end
        },
        -- 光模块功耗信息(SFF8636)
        OpticalPowerInfoSFF8636 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 60,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x5d00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x2500 -- 取37个字节数据
                }, true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8,
                    i2c_addres:8,
                    page_number:8,
                    dev_address:16,
                    page_lock_field:8,
                    operation:8,
                    transfer_size:16,
                    full_enable:8,
                    _:35/string,
                    power_class:8
                >>]]):unpack(data, true)
                if not r then return nil end
                local legacy_power_class = (r.power_class & 0xc0) >> 6
                local full_power_class = r.power_class & 0x03
                local enabled_flag = (r.full_enable & 0x04) >> 2
                if enabled_flag == 0 or full_power_class == 0 then
                    return {
                        PowerClass = legacy_power_class + 1
                    }
                end
                return {
                    PowerClass = full_power_class + 4
                }
            end
        },
        -- 光模块电压(CMIS)
        OpticalVoltageCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x1000,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0200 -- 取2个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_data_rsp:unpack(data, true)
                if not r then return nil end
                local voltage_base <const> = 0.0001
                return r.data * voltage_base
            end
        },
        -- 光模块厂商、部件编码等信息(CMIS)
        OpticalStaticInfoCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 60,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x8100,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x3500 -- 取53个字节数据
                }, true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8,
                    i2c_addres:8,
                    page_number:8,
                    dev_address:16,
                    page_lock_field:8,
                    operation:8,
                    transfer_size:16,
                    vendor_name:16/string,
                    vendor_oui:3/string,
                    vendor_pn:16/string,
                    vendor_rev:2/string,
                    vendor_sn:16/string
                >>]]):unpack(data, true)
                if not r then return nil end
                return {
                    Manufacturer = trim(r.vendor_name),
                    PartNumber = trim(r.vendor_pn),
                    SerialNumber = trim(r.vendor_sn),
                    RevisionNumber = trim(r.vendor_rev)
                }
            end
        },
        -- 光模块连接器类型(CMIS)
        OpticalConnectorTypeCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 60,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0xcb00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100 -- 取1个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_date_rsp:unpack(data, true)
                if not r then return nil end
                return connector_switch[r.data] or ''
            end
        },
        -- 光模块功耗信息(CMIS)
        OpticalPowerInfoCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 60,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0xc800,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0200 -- 取2个字节数据
                }, true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8,
                    i2c_addres:8,
                    page_number:8,
                    dev_address:16,
                    page_lock_field:8,
                    operation:8,
                    transfer_size:16,
                    power_class:8,
                    max_power:8
                >>]]):unpack(data, true)
                if not r then return nil end
                local max_power_base <const> = 0.25
                local power_class_value = (r.power_class & 0xe0) >> 5
                local max_power_value = r.max_power * max_power_base
                return {
                    PowerClass = power_class_value + 1,
                    PowerCapacityWatts = max_power_value
                }
            end
        },
        -- 光模块状态信息(CMIS)
        OpticalModuleStateCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x0300,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x0100 -- 取1个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_date_rsp:unpack(data, true)
                if not r then return nil end
                local module_state = (r.data & 0x0e) >> 1
                return module_state
            end
        },
        -- 光模块偏置电流(CMIS)
        OpticalBiasCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x11,
                    dev_address = 0xaa00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x1000 -- 取16个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_channel_info_cmis_rsp:unpack(data, true)
                if not r then return nil end
                local bias_base <const> = 0.002
                return {
                    r.channel1_data * bias_base,
                    r.channel2_data * bias_base,
                    r.channel3_data * bias_base,
                    r.channel4_data * bias_base,
                    r.channel5_data * bias_base,
                    r.channel6_data * bias_base,
                    r.channel7_data * bias_base,
                    r.channel8_data * bias_base
                }
            end
        },
        -- 光模块输入功率(CMIS)
        OpticalInputPowerCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x11,
                    dev_address = 0xba00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x1000 -- 取16个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_channel_info_cmis_rsp:unpack(data, true)
                if not r then return nil end
                local input_power_base <const> = 0.0001
                return {
                    r.channel1_data * input_power_base,
                    r.channel2_data * input_power_base,
                    r.channel3_data * input_power_base,
                    r.channel4_data * input_power_base,
                    r.channel5_data * input_power_base,
                    r.channel6_data * input_power_base,
                    r.channel7_data * input_power_base,
                    r.channel8_data * input_power_base
                }
            end
        },
        -- 光模块输出功率(CMIS)
        OpticalOutputPowerCMIS50 = {
            protocol = 'ncsi_mellanox',
            action = 'on_schedule',
            period_in_sec = 2,
            request = {
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x11,
                extra_cmd = 0x0,
                data = date_req:pack({
                    i2c_address = 0x50,
                    page_number = 0x0,
                    dev_address = 0x9a00,
                    page_lock_field = 0x0,
                    operation = 0x0,
                    transfer_size = 0x1000 -- 取16个字节数据
                }, true)
            },

            response = function(data)
                local r = optical_get_channel_info_cmis_rsp:unpack(data, true)
                if not r then return nil end
                local output_power_base <const> = 0.0001
                return {
                    r.channel1_data * output_power_base,
                    r.channel2_data * output_power_base,
                    r.channel3_data * output_power_base,
                    r.channel4_data * output_power_base,
                    r.channel5_data * output_power_base,
                    r.channel6_data * output_power_base,
                    r.channel7_data * output_power_base,
                    r.channel8_data * output_power_base
                }
            end
        },
        -- 获取Host Access状态
        -- 0x00为Disable，0x01为Enable
        GetHostAccess = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x19,
                extra_cmd = 0x0
            },

            response = function(data)
                local r = host_access_rsp:unpack(data, true)
                if not r or not r.host_access_state then
                    return 0xff
                end
                if r.host_access_state ~= 0x00 and r.host_access_state ~= 0x01 then
                    return 0xfe
                end
                return r.host_access_state
            end
        },
        -- 设定Host Access状态
        -- host_access_state设定0x00为Disable，0x01为Enable

        -- 设定Host Access状态为Disable
        SetHostAccessDisable = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x12,
                parameter = 0x19,
                extra_cmd = 0x0,
                data = set_host_access_req:pack({
                    reserved = 0x000000,
                    host_access_state = 0x00
                },true)
            },
            response = function(data)
                local r = host_access_rsp:unpack(data, true)
                if not r or not r.host_access_state then
                    return 0xff
                elseif r.host_access_state == 0x00 or r.host_access_state == 0x01 then
                    return r.host_access_state
                end
                return 0xfe
            end
        },
        -- 设定Host Access状态为Enable
        SetHostAccessEnable= {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x12,
                parameter = 0x19,
                extra_cmd = 0x0,
                data = set_host_access_req:pack({
                    reserved = 0x000000,
                    host_access_state = 0x01
                },true)
            },
            response = function(data)
                local r = host_access_rsp:unpack(data, true)
                if not r or not r.host_access_state then
                    return 0xff
                elseif r.host_access_state == 0x00 or r.host_access_state == 0x01 then
                    return r.host_access_state
                end
                return 0xfe
            end
        },

        -- 获取Extended Host Privilege状态
        -- 1 为Enable 返回 0x01，2 为Disable 返回0x00，0为default模式，返回0xf0
        GetExtendedHostPrivilege = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x32,
                extra_cmd = 0x0
            },

            response = function(data)
                local r = get_extended_host_privilege_rsp:unpack(data, true)
                if not r or not r.external_host_parameters_change then
                    return 0xff
                end
                if r.external_host_parameters_change == 1 then
                    return 0x01
                elseif  r.external_host_parameters_change == 2 then
                    return 0x00
                elseif  r.external_host_parameters_change == 0 then
                    return 0xf0
                end
                return 0xfe
            end
        },

        -- 设定Extended Host Privilege状态
        -- external_host_parameters_change设置0为Disable，1为Enable

        -- 设定Extended Host Privilege状态为Disable
        SetExtendedHostPrivilegeDisable = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x12,
                parameter = 0x32,
                extra_cmd = 0x0,
                data = set_extended_host_privilege_req:pack({
                    nic_reset = 0,
                    nic_fw_update = 0,
                    pcc_fw_update = 0,
                    emb_cpu_setting_change = 0,
                    global_non_volatile_change = 0,
                    network_port_parameters_change = 0,
                    external_host_parameters_change = 2,
                    nic_flash_access = 0,
                    reserved = 0x0000
                },true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8
                >>]]):unpack(data, true)
                return r ~= nil
            end
        },
        -- 设定Extended Host Privilege状态为Enable
        SetExtendedHostPrivilegeEnable = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x12,
                parameter = 0x32,
                extra_cmd = 0x0,
                data = set_extended_host_privilege_req:pack({
                    nic_reset = 0,
                    nic_fw_update = 0,
                    pcc_fw_update = 0,
                    emb_cpu_setting_change = 0,
                    global_non_volatile_change = 0,
                    network_port_parameters_change = 0,
                    external_host_parameters_change = 1,
                    nic_flash_access = 0,
                    reserved = 0x0000
                },true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8
                >>]]):unpack(data, true)
                return r ~= nil
            end
        },

        -- 获取BF3的Mode
        -- offload_engine为 0 代表CPU启用为offload engine，此时为DPU mode 返回 0x01
        -- offload_engine为 1 代表CPU禁用为offload engine，此时为NIC mode 返回 0x00
        GetMode = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x13,
                parameter = 0x33,
                extra_cmd = 0x0
            },

            response = function(data)
                local r = get_mode_rsp:unpack(data, true)
                if not r or not r.offload_engine then
                    return 0xff
                end
                if r.offload_engine == 0 then
                    return 0x01
                elseif  r.offload_engine == 1 then
                    return 0x00
                end
                    return 0xfe
            end
        },
        -- 设定BF3的Mode
        -- 将模式设定为NIC
        SetModeFromDPUToNIC = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x12,
                parameter = 0x33,
                extra_cmd = 0x0,
                data = set_mode_req:pack({
                    reserved_1 = 0,
                    reserved_2 = 0,
                    offload_engine = 1
                },true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8
                >>]]):unpack(data, true)
                return r ~= nil
            end
        },
        -- 将模式设定为DPU
        SetModeFromNICToDPU = {
            protocol = 'ncsi_mellanox',
            action = 'on_demand',
            request = {
                channel_id = 0x1F,
                cmd_mellanox = 0x00,
                mellanox_cmd_id = 0x12,
                parameter = 0x33,
                extra_cmd = 0x0,
                data = set_mode_req:pack({
                    reserved_1 = 0,
                    reserved_2 = 0,
                    offload_engine = 0
                },true)
            },

            response = function(data)
                local r = bs.new([[<<
                    reserved:8
                >>]]):unpack(data, true)
                return r ~= nil
            end
        }
    }
}

return {
    smbus = nil,
    mctp = function(endpoint)
        local bf3 = CX5.mctp(endpoint)
        for k, v in pairs(BF3.properties) do
            bf3.properties[k] = v
        end
        return bf3
    end
}