-- 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> = 0x07
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 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
        }
    }
}

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