创芯科技USB_CAN【库文件】

只用到【只收】【只发】功能

23.11.18

using help;
//using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


// 1先引用  CAN_namespace   用于参数类型 //  using USB_CAN;
// 2再引用 help的方法

namespace CAN_namespace
{
    #region 全局类型【声明】:通讯接口
    /// <summary>
    /// 全局类型:通讯接口
    /// </summary>
    public interface Iface_RTX  // 开,关,收,发,轮询
    {
        /// <summary>
        /// 连接
        /// </summary>
        /// <typeparam name="T">连接</typeparam>
        /// <param name="a">ip地址</param>
        /// <param name="b">端口</param>
        /// <returns></returns>
        bool connect<T>(T a, T b);

        /// <summary>
        /// 断开
        /// </summary>
        /// <returns></returns>
        bool Close();

        /// <summary>
        /// 只收
        /// </summary>
        /// <returns></returns>
        int RXs(ref object obj);
        //int RXs<T>(ref T obj);//测试

        /// <summary>
        /// 只发,格式148报文
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        bool TXs(string cmd);

        /// <summary>
        /// 轮询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cmd"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        bool sendAndReceive<T>(string cmd, ref T t);//万物皆文本

    }
    #endregion
    #region 对象
    public class Help_USB_CAN : Iface_RTX
    {//作者qq750273008 祁成  更新日期:2023.11.13
        //===============================================
        //[Browsable(true)]    //可浏览
        //[Category("自定义属性")]   // 属性分栏
        //[Description("属性的说明")]   //
        //================================================
        #region 全局
        //1申明委托》委托命令
        public delegate void WT_GET_Data<T>(T ciA402);//↑ui显示发送命令
        public delegate void WT_SET_Data(byte[] butes, string data);//↓下执行对象

        #region CAN参数类型:全局;【设备类型,主板信息,单帧信息,配置表



        /*------------兼容ZLG的数据类型---------------------------------*/
        //1.设备类型
        /// <summary>
        /// 设备类型(单路,双路,以太网CAN)
        /// </summary>
        public enum DeviceType : byte   //设备类型【USB的【单路,双路】,以太网的【单路,双路】can】
        {
            DEV_USBCAN = 3, // USB单路CAN
            DEV_USBCAN2 = 4,// USB双路CAN

            VCI_USBCAN1 = 3,
            VCI_USBCAN2 = 4,// 我买的属于这个(创新科技CAN-Pro)
            VCI_USBCAN2A = 4,
            VCI_USBCAN_E_U = 20,// 以太网单路CAN
            VCI_USBCAN_2E_U = 21// 以太网双路CAN
        }
        //设备类型
        public enum CAN设备类型 : int
        {
            DEV_USBCAN = 3, // USB单路CAN
            DEV_USBCAN2 = 4,// USB双路CAN

            VCI_USBCAN1 = 3,
            VCI_USBCAN2 = 4,
            VCI_USBCAN2A = 4,
            VCI_USBCAN_E_U = 20,// 以太网单路CAN
            VCI_USBCAN_2E_U = 21// 以太网双路CAN

        }

        //2.ZLGCAN系列接口卡信息的数据类型。
        /// <summary>
        /// 主板设备【31F01031C93】v3.41  VCI_ReadBoardInfo
        /// </summary>
        public struct VCI_BOARD_INFO //主板信息
        { // VCI_ReadBoardInfo【要先运行VCI_OpenDevice(4,0,0);】   VCI_FindUsbDevice2
            public UInt16 hw_Version;//【0x0900】硬件版本,比如0x0100表示V1.00。
            public UInt16 fw_Version;//【0x0341】固件版本,v3.41
            public UInt16 dr_Version;//【0x0900】驱动版本,
            public UInt16 in_Version;//【0x0905】接口版本,
            public UInt16 irq_Num;//   【0x00】  保留参数。
            public byte can_Num;  //   【0x02】  表示有几路CAN通道。
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public char[] str_Serial_Num;// 板卡序列号。【31F01031C93】

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
            public char[] str_hw_Type;// 硬件类型【55 53 42 43 41 4e 2d 49 49】“USBCAN-II”

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public UInt16[] Reserved;// 系统保留。
        }

        //2-1.USB-CAN总线适配器板卡信息的数据类型1,该类型为VCI_FindUsbDevice函数的返回参数。
        /// <summary>
        /// USB-CAN设备主板信息,该类型为VCI_FindUsbDevice函数的返回参数。
        /// </summary>
        public struct VCI_BOARD_INFO1 // 读取USB主板信息 设备【31F01031C93】v3.41
        {// VCI_FindUsbDevice

            public UInt16 hw_Version;//【0x0900】 硬件版本,0x0100表示V1.00。 // 
            public UInt16 fw_Version;//【0x0341】 固件版本,v3.41, 
            public UInt16 dr_Version;//【0x0900】 驱动版本,
            public UInt16 in_Version;//【0x0905】 接口版本, 
            public UInt16 irq_Num;//   【0x0000】 保留参数。
            public byte can_Num;//     【0x02】   表示有几路CAN通道。
            public byte Reserved;//    【0x00】   保留。
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public char[] str_Serial_Num;// 此板卡的序列号。【43 41 4e 2d 31 43 39 33】"CAN-1C93"

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public char[] str_hw_Type;// 硬件类型“USBCAN V1.00”【55 53 42 43 41 4e 2d 49 49】"USBCAN-II"

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public char[] str_Usb_Serial;// 序列号【31 43 39 33】// "1C93"
        }
        //3.定义CAN每帧的数据类型。
        /// <summary>
        /// CAN的每一帧详细信息(每帧对象)
        /// </summary>
        public unsafe struct VCI_CAN_OBJ  //CAN每帧对象,
        {
            public uint ID;// 帧ID。        【u32】帧id,数据格式为靠右对齐。 详情请参照: 《8.附件1: ID对齐方式.pdf》说明文档。
            public uint TimeStamp;        //【u32】设备时间标识。 时间标示从CAN卡上电开始计时,计时单位为0.1ms。
            public byte TimeFlag;         //是否使用时间标识,=1时TimeStamp有效
            public byte SendType;         //发送类型。=0时为正常发送(重发超时时间为1秒,1秒内没有发出则取消);=1时为单次发送
            public byte RemoteFlag;       //是否远程帧标志。 =0时为数据帧, =1时为远程帧(数据段空)。
            public byte ExternFlag;       //是否扩展帧标志。 =0时为标准帧(11位ID), =1时为扩展帧(29位ID)。
            public byte DataLen;          //有效字节 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中有效字节数。
            public fixed byte Data[8];    //数据包,如DataLen定义为3,即Data[0]、 Data[1]、 Data[2]是有效的。
            public fixed byte Reserved[3];//系统保留。
        }

        //4.定义配置CAN的数据类型
        /// <summary>
        /// USB-CAN2、配置表(参数表)
        /// </summary>
        public struct VCI_INIT_CONFIG // 配置参数 设备【31F01031C93】v3.41
        {
            public UInt32 AccCode;// bit全部匹配,此帧才可以被接收。否则不能接收。(//标准帧右移21bit分析)
                                  // 相当于机械钥匙,凸起和凹槽必须匹配,才能开锁(接收)
                                  // b31对应帧id最高位,所以11bit要左移21bit(//分析标准帧时右移21bit)
            public UInt32 AccMask;// 屏蔽码。使AccCode的某个bit功能失效。左对齐,bit31~bit21置1为屏蔽AccCode的bit匹配功能,
                                  // 相当于机械钥匙的bit销位,是否失效(bit置1为失效)
                                  // 。屏蔽码推荐设置为0xFFFFFFFF,即全部接收。
            public UInt32 Reserved;// 保留。
            public byte Filter;   // 1接收所有帧。2只收标准帧,3只收扩展帧。
            public byte Timing0;  //波特率参数,具体配置,请查看二次开发库函数说明书。(1Mbps):《Timing0=0x00,Timing1=0x14》
            public byte Timing1;    // 0x14       波特率参数 1MHz(T0=0x00,T1=0x14)
            public byte Mode;     //模式,0表示正常模式,1表示只听模式,2自测模式(环回模式)。
        }
        /*------------其他数据结构描述---------------------------------*/
        public struct CHGDESIPANDPORT // 扩展端口?
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
            public byte[] szpwd;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] szdesip;
            public Int32 desport;

            public void Init()
            {
                szpwd = new byte[10];
                szdesip = new byte[20];
            }
        }

        public struct VCI_FILTER_RECORD //滤帧配置
        {
            UInt32 ExtFrame;// 过滤的帧类型【1】过滤扩展帧【0】过滤标准帧。
            UInt32 Start;//起始帧ID 
            UInt32 End;  //结束帧ID 
        }

        /*------------数据结构描述完成---------------------------------*/



        #endregion

        #endregion
        #region 字段
        //private CancellationTokenSource cts;//线程令牌
        //private ManualResetEvent resetEvent = new ManualResetEvent(true);// 暂停业务
        //=====================================================
        Help_String help_String = new Help_String();//文本处理
        //设备类型
        public const int VCI_USBCAN = 3;// USB单路CAN
        public const int VCI_USBCAN2 = 4;// USB双路CAN
        // E表示以太网
        public const int VCI_USBCAN_E_U = 20;// 以太网单路CAN
        public const int VCI_USBCAN_2E_U = 21;// 以太网双路CAN

        const uint CAN1 = 0; // 字段,内部使用
        const uint CAN2 = 1;
        const byte STATUS_OK = 1;
        const byte STATUS_ERR = 0;
        #endregion
        #region 属性
        //public Iface_RTX help_rtx { get; set; }// 接口扩展
        /// <summary>
        /// ↑:byte包,文本
        /// </summary>
        //static public WT_GET_Data  Wt_get;//↑event委托=》呼叫上ui层  让上层显示:发送命令
        /// <summary>
        /// ↓:byte包,文本
        /// </summary>
        static public WT_SET_Data Wt_set;//↓委托=》呼叫下位机执行

        public VCI_BOARD_INFO1[] get_FindUsbDevice
        {
            get
            {
                VCI_BOARD_INFO1[] pInfo = new VCI_BOARD_INFO1[5];
                Int32 num = VCI_FindUsbDevice(ref pInfo[0]);// 查找5个设备
                return pInfo;
            }
        }
        /// <summary>
        /// USB设备id:查找50个USB设备【31F01031C93】
        /// </summary>
        public VCI_BOARD_INFO[] get_FindUsbDevice2
        {
            get
            {
                VCI_BOARD_INFO[] pInfo = new VCI_BOARD_INFO[50];
                UInt32 num = VCI_FindUsbDevice2(ref pInfo[0]);// 查找50个设备
                return pInfo;
            }
        }
        public VCI_BOARD_INFO get_ReadBoardInfo
        {
            get
            {
                Set_Open();
                VCI_BOARD_INFO info = new VCI_BOARD_INFO();
                Int32 num = VCI_ReadBoardInfo(VCI_USBCAN2, 0, ref info);
                return info;

            }
        }

        #endregion
        #region 构造

        #endregion
        #region 事件

        #endregion

        #region APP方法【 开,关,收,发,复位
        /// <summary>
        /// 打开CAN:设备类型,硬件id,CAN通道id,参数表
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="CANInd"></param>
        /// <param name="pInitConfig"></param>
        /// <returns></returns>
        public Int32 Set_Open()//(DeviceType deviceType, uint deviceID,uint canX, VCI_INIT_CONFIG Config)// 设备类型,设备id,通道,配置参数
        {//打开CAN:设备类型,硬件索引,CAN通道索引,初始化参数,
            //查找CAN并打开can1通道

            Int32 sta = 1;// 故障标记
            UInt32 DeviceType = (int)VCI_USBCAN2;// 设备类型4【USB双路CAN】
            UInt32 DeviceInd = 0;// 设备ID

            VCI_BOARD_INFO1 bord = new VCI_BOARD_INFO1();// 设备信息【结构体】
            int num = VCI_FindUsbDevice(ref bord);// 查找USB设备【31F01031C93】v3.41
            if (num < 1)
            {// 找不到设备
                return 0;
            }

            // 配置表
            VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();// 参数表【结构体】
            // bit全部匹配,此帧才可以被接收。否则不能接收。【左对齐】(//标准帧右移21bit分析)
            config.AccCode = 0;//bit【钥匙销子】匹配id,(右移21bit分析【32-11】)b31对应帧id最高位【左对齐】
            config.AccMask = 0xffffffff;// 屏蔽码。使AccCode的某个bit功能失效。左对齐,【标准帧11bit】bit31~bit21置1为屏蔽AccCode的bit匹配功能,
            config.Filter = 1;//0或1接收所有帧。2只接收标准帧,3只接收扩展帧。
            config.Timing0 = 0x00;//波特率 1MHz【T0=0x00,T1=0x14】  // 查手册
            config.Timing1 = 0x14;
            config.Mode = 0;//模式,0表示正常模式,1表示只听模式,2表示自发自收模式(环回模式)

            // usb硬件
            sta &= VCI_使能设备(DeviceType, DeviceInd);// 通电

            sta &= VCI_初始化通道(DeviceType, DeviceInd, CAN1, ref config);// CAN 1
            sta &= VCI_初始化通道(DeviceType, DeviceInd, CAN2, ref config);// CAN 2

            sta &= VCI_CAN通道工作(DeviceType, DeviceInd, CAN1);// CAN 1
            //sta &= VCI_CAN通道工作(DeviceType, DeviceInd, CAN2);// CAN 2

            // 硬件信息【在VCI_OpenDevice运行后才可读设备信息】
            VCI_BOARD_INFO pInfo = new VCI_BOARD_INFO();// 设备信息
            Int32 num1 = VCI_ReadBoardInfo(4, 0, ref pInfo);//   VCI_ReadBoardInfo     VCI_FindUsbDevice
            if (num1 >= 1)
            {
                string 序列号 = new string(pInfo.str_Serial_Num);
                string 设备名称 = new string(pInfo.str_hw_Type);
            }


            return (Int32)(sta == 1 ? 1 : 0);// 1完成,0故障

            //================================
            //VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();// 参数表
            //config.AccCode = 0;// bit全部匹配,此帧才可以被接收。否则不能接收。【左对齐】(//标准帧右移21bit分析)
            //config.AccMask = 0xffffffff;//全部接收  // 屏蔽码。使AccCode的某个bit功能失效。左对齐,bit31~bit21置1为屏蔽AccCode的bit匹配功能,
            //config.Filter = 0;//0或1接收所有帧。2标准帧滤波,3是扩展帧滤波。
            //config.Timing0 = 0x00;//波特率参数 1MHz(T0=0x00,T1=0x14)
            //config.Timing1 = 0x14;
            //config.Mode = 0;//模式,0表示正常模式,1表示只听模式,2自测模式

            //uint i = can.set_Open(Help_USB_CAN.VCI_USBCAN2, 0, 0, ref config);// CAN 1
            //i &= can.set_Open(Help_USB_CAN.VCI_USBCAN2, 0, 1, ref config);// CAN 2

        }
        /// <summary>
        /// 关闭CAN:设备类型,设备id
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <returns></returns>
        public Int32 Set_Close(UInt32 DeviceType, UInt32 DeviceInd)// UInt32 DeviceType, UInt32 DeviceInd
        {
            Int32 sta = 1;// 故障标记

            sta &= VCI_CloseDevice(DeviceType, DeviceInd);//设备关
            sta &= VCI_UsbDeviceReset(DeviceType, DeviceInd, 0);// 设备复位

            return sta;
        }
        public Int32 Set_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd)
        {//设备类型,设备id,通道id
            Int32 sta = 1;
            sta &= VCI_ClearBuffer(DeviceType, DeviceInd, CANInd);
            //sta&= VCI_ClearBuffer(DeviceType, DeviceInd, 1);// CAN2
            return sta;
        }
        /// <summary>
        /// 接收:设备类型,设备索引,CAN通道索引,参数表,最大帧数2000,超时时间
        /// </summary>
        /// <param name="DeviceType">设备类型</param>
        /// <param name="DeviceInd">设备id</param>
        /// <param name="CANInd">通道id</param>
        /// <param name="pReceive">数据包</param>
        /// <param name="Len">小于2500帧</param>
        /// <param name="WaitTime">保留=0</param>
        /// <returns></returns>
        public Int32 get_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime)
        {//VCI_CAN_OBJ pReceive 设置为数组,2000帧
            // 设备类型,设备id,通道id,数据包,帧数,等待时间【保留0】
            return VCI_Receive(DeviceType, DeviceInd, CANInd, ref pReceive, Len, WaitTime);
        }
        /// <summary>
        /// 发送:设备类型,设备索引,CAN通道索引,参数表,要发帧数
        /// </summary>
        /// <param name="DeviceType">设备类型</param>
        /// <param name="DeviceInd">设备id</param>
        /// <param name="CANInd">通道id</param>
        /// <param name="pSend">数据包</param>
        /// <param name="Len">帧数小于1000</param>
        /// <returns></returns>
        public Int32 set_Send(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len)
        {
            // 设备类型,设备id,通道id,数据包,帧数
            return VCI_Transmit(DeviceType, DeviceInd, CANInd, ref pSend, Len);
        }
        public Int32 set_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd)
        {// 复位can通道
            return VCI_ResetCAN(DeviceType, DeviceInd, CANInd);
        }
        /// <summary>
        /// 获取CAN设备信息【需要先打开设备】
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="pInfo"></param>
        /// <returns></returns>
        public Int32 get_BoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo)
        {//需要设备开启后,才能读取
            return VCI_ReadBoardInfo(DeviceType, DeviceInd, ref pInfo);
            //=======================================================
            //VCI_BOARD_INFO info = new VCI_BOARD_INFO();
            //uint i = can.get_Board(4, 0, ref info);

        }


        //==以下不再重要=======================================================================
        //==以下不再重要========




        /// <summary>
        /// 使能硬件:设备类型,设备id。
        /// </summary>
        /// <param name="DeviceType">Help_USB_CAN.VCI_USBCAN2 = 4;双路CAN</param>
        /// <param name="DeviceInd">第1个CAN通道是0</param>
        /// <param name="Reserved">备用=0</param>
        /// <returns></returns>
        public Int32 VCI_使能设备(UInt32 DeviceType, UInt32 DeviceInd)
        {// 相当于 插电
            return VCI_OpenDevice(DeviceType, DeviceInd, 0x00);// 通电
        }
        /// <summary>
        /// 初始化硬件:can设备类型,设备id,CAN通道id,VCI_INIT_CONFIG初始化参数结构体
        /// </summary>
        /// <param name="DeviceType">can设备类型</param>
        /// <param name="DeviceInd">设备索引0</param>
        /// <param name="CANInd">CAN通道索引0</param>
        /// <param name="pInitConfig">VCI_INIT_CONFIG初始化参数结构</param>
        /// <returns></returns>
        public Int32 VCI_初始化通道(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig)
        {
            return VCI_InitCAN(DeviceType, DeviceInd, CANInd, ref pInitConfig);
        }
        //设备类型。设备索引,CAN通道索引。初始化参数结构。

        /// <summary>
        /// CAN工作:设备类型,设备id,CAN通道id(返回【1】成功; 【0】失败; 【-1】设备不存在或USB掉线。)
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="CANInd"></param>
        /// <returns></returns>
        public Int32 VCI_CAN通道工作(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd)
        {
            return VCI_StartCAN(DeviceType, DeviceInd, CANInd);
        }

        /// <summary>
        /// CAN发送:设备类型,设备索引,CAN通道索引,VCI_CAN_OBJ数组的首指针,(帧数量 最大为10)
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="CANInd"></param>
        /// <param name="pSend"></param>
        /// <param name="Len"></param>
        /// <returns></returns>
        public Int32 VCI_set发送(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len)
        {
            return VCI_Transmit(DeviceType, DeviceInd, CANInd, ref pSend, Len);
        }

        public Int32 VCI_get缓存区帧数(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd)
        {
            return VCI_GetReceiveNum(DeviceType, DeviceInd, CANInd);// 缓存区,帧数
        }
        /// <summary>
        /// CAN接收:设备类型,设备id,CAN通道id,VCI_CAN_OBJ数组的首指针,本次接收的最大帧数 2500 ,超时时间ms
        /// </summary>
        /// <param name="DeviceType"></param>
        /// <param name="DeviceInd"></param>
        /// <param name="CANInd"></param>
        /// <param name="pReceive"></param>
        /// <param name="Len"></param>
        /// <param name="WaitTime"></param>
        /// <returns></returns>
        public Int32 VCI_get接收(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime)
        {
            //VCI_CAN_OBJ[] obj = new VCI_CAN_OBJ[2000];
            //uint i = can.VCI_get接收(4, 0, 1, ref obj[0], 2000, 0);
            return VCI_Receive(DeviceType, DeviceInd, CANInd, ref pReceive, Len, WaitTime);
        }

        #endregion

        #region 后台方法
        #region 元始库方法

        //方法
        /*------------兼容ZLG的函数描述---------------------------------*/
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
        //返回值=1,表示操作成功;=0表示操作失败;=-1表示USB-CAN设备不存在或USB掉线。
        //使能设备//(can通道不工作,只设备工作)
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
        //返回值=1,表示操作成功;=0表示操作失败;=-1表示USB-CAN设备不存在或USB掉线。
        //关闭设备
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);
        //初始化can通道(参数配置)b31对应帧id最高位,所以11bit要左移21bit
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);
        //读取主板信息【需要先VCI_OpenDevice】
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        //缓存区可用帧数(<=2000帧)
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        //清空缓存区
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        //CAN通道启动(启动can通道)
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
        //CAN通道复位
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_Transmit(UInt32 DeviceType,UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend,UInt32 Length);
        //返回实际发送的帧数,=-1表示USB-CAN设备不存在或USB掉线。
        //Length 最大为1000,建议设为1,每次发送单帧,以提高发送效率
                //CAN通道发送(单次<=10帧)
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);
        //CAN通道接收(函数调用间隔至少应设置在5ms以上。)【Len为单次封顶帧数2500帧被读出

        /*------------其他函数描述---------------------------------*/
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_ConnectDevice(UInt32 DevType, UInt32 DevIndex);
        //设备连接
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_UsbDeviceReset(UInt32 DevType, UInt32 DevIndex, UInt32 Reserved);
        //设备复位
        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
        //返回前5个设备信息
        //若计算机中插入多于5个适配器,则使用VCI_FindUsbDevice2函数,最大支持50个USB-CAN适配器。
        [DllImport("controlcan.dll")]
        public static extern UInt32 VCI_FindUsbDevice2 (ref VCI_BOARD_INFO pInfo);
        //如:VCI_BOARD_INFO pInfo[50]。 

        [DllImport("controlcan.dll")]
        public static extern Int32 VCI_SetReference(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, UInt32 RefType, ref VCI_FILTER_RECORD pData);
        //设置滤帧(设备类型,设备id,通道id,参数类型,参数包)【只监听某一范围的帧】
        //RefType=1,添加滤帧表 指向VCI_FILTER_RECORD结构的指针
        //RefType=2,启用滤帧表
        //RefType=3,清除滤帧表。

        /*------------函数描述结束---------------------------------*/

        #endregion
        #endregion


        #region 窗体移动

        //private Point mouseOff;//鼠标移动位置变量
        //private bool leftFlag;//标签是否为左键
        //private void Frm_MouseDown(object sender, MouseEventArgs e)//鼠标按下
        //{
        //    if (e.Button == MouseButtons.Left)
        //    {
        //        mouseOff = new Point(-e.X, -e.Y); //得到变量的值
        //        leftFlag = true;                  //点击左键按下时标注为true;
        //    }
        //}
        //private void Frm_MouseMove(object sender, MouseEventArgs e)//鼠标移动
        //{
        //    if (leftFlag)
        //    {
        //        Point mouseSet = Control.MousePosition;
        //        mouseSet.Offset(mouseOff.X, mouseOff.Y);  //设置移动后的位置
        //                                                  //Location = mouseSet;//Form 窗体父类字段
        //    }
        //}
        //private void Frm_MouseUp(object sender, MouseEventArgs e)//鼠标松开
        //{
        //    if (leftFlag)
        //    {
        //        leftFlag = false;//释放鼠标后标注为false;
        //    }
        //}

        #endregion

        #region 错误
        //try
        //{
        //    byte[] buffer = Encoding.Default.GetBytes(data);//以计算机的编码发送
        //    serialPort.Write(buffer, 0, buffer.Length);//  开始发送
        //}
        //catch (Exception ex) { MessageBox.Show(ex.Message); }//显示错误
        #endregion

        #region 接口实现

        public bool connect<T>(T a, T b)
        {// 打开USB-CAN设备的can1通道

            //throw new NotImplementedException();
            int sta = Set_Open();
            return sta == STATUS_OK ? true : false; // 1完成,0故障
        }

        bool Iface_RTX.Close()
        {
            //throw new NotImplementedException();
            if (Set_Close(VCI_USBCAN2, 0) == 1)
            {
                return true;
            }
            return false;
        }
      
        public Int32 RXs(ref object Obj)
        {
            //throw new NotImplementedException();
            // 缓存区可用帧数=============================
            
            //int i = VCI_GetReceiveNum(Help_USB_CAN.VCI_USBCAN2, CAN_inD, CAN1);// can1

            VCI_CAN_OBJ[] obj = new VCI_CAN_OBJ[2500];// 创新科技CAN分析仪,单次最大缓存2500帧接收,间隔5ms以上
            Int32 num = VCI_get接收(VCI_USBCAN2, 0, CAN1, ref obj[0], 2500, 0);//  注意 CAN1  通道
            if (num > 0)// CAN1接收帧数
            {
                Obj = obj;
                return num;

                #region 取一帧      【1   4    8】
                //=================================================
                //byte[] bytes = new byte[13];
                //bytes[0] = obj[0].DataLen;   //  【1】有效字节
                //uint id = obj[0].ID; //     帧 id【4】帧id
                //bytes[1] = (byte)(id >> 24);
                //bytes[2] = (byte)(id >> 16);
                //bytes[3] = (byte)(id >> 8);
                //bytes[4] = (byte)(id & 0xff);

                //fixed (VCI_CAN_OBJ* p_obj = &obj[0])// 8字节    第一帧
                //{
                //    bytes[5] = p_obj->Data[0];//  【8】包数据
                //    bytes[6] = p_obj->Data[1];
                //    bytes[7] = p_obj->Data[2];
                //    bytes[8] = p_obj->Data[3];
                //    bytes[9] = p_obj->Data[4];
                //    bytes[10] = p_obj->Data[5];
                //    bytes[11] = p_obj->Data[6];
                //    bytes[12] = p_obj->Data[7];
                //}
                //return bytes;

                #endregion

            }

            return 0;
        }
        //public int RXs<T>(ref T obj)// 待测试
        //{
        //    //throw new NotImplementedException();
        //    VCI_CAN_OBJ[] obj2 = new VCI_CAN_OBJ[2000];// 创新科技CAN分析仪最大支持2000帧接收,间隔5ms以上
        //    int num = VCI_get接收(4, 0, CAN1, ref obj2[0], 2000, 50);
        //    if (num > 0)// CAN1接收帧数
        //    {
        //        //obj = obj2.ToList<T>();

        //        return num;
        //    }
        //    return 0;


        //    }
        public unsafe bool TXs(string cmd)//  "08   00000602  4064600000000000"   //   CAN_namespace.Iface_RTX.
        {// 1  4  8 (DLC字节,帧id,Byte8数据包)
            //throw new NotImplementedException();
            cmd.Replace(" ", "");//去除空白
            byte[] buffercmd = help_String.StringsToHexBytes(cmd);//准备报文  //去除空白   StringsToHexBytes
            VCI_CAN_OBJ[] buffer = new VCI_CAN_OBJ[10];
            string id = cmd.Substring(2, 8);// 从站地址  00000602
            // 4   
            buffer[0].ID = Convert.ToUInt32(id, 16);//从站id
            // 重发功能 0开,1关
            buffer[0].SendType = 0;//【0】正常,失败有重发  【1】只发单次,失败无重发
            // 1      
            buffer[0].DataLen = buffercmd[0];//数据长度 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节。
            // 8           
            buffer[0].Data[0] = buffercmd[5];// byte8
            buffer[0].Data[1] = buffercmd[6];
            buffer[0].Data[2] = buffercmd[7];
            buffer[0].Data[3] = buffercmd[8];
            buffer[0].Data[4] = buffercmd[9];
            buffer[0].Data[5] = buffercmd[10];
            buffer[0].Data[6] = buffercmd[11];
            buffer[0].Data[7] = buffercmd[12];
            // 上车
            Int32 ret = VCI_set发送(Help_USB_CAN.VCI_USBCAN2, 0, CAN1, ref buffer[0], 1);// 库函数(发送TXs)
            if (ret == 1) return true;

            return false;
        }


        public unsafe object sendAndReceive(string stringcmd)
        {//"1803052000018705"
            //"04000006014000200000000000"
            //throw new NotImplementedException();
            stringcmd.Replace(" ", "");//去除空白
            byte[] buffercmd = help_String.StringsToHexBytes(stringcmd);//准备报文  //去除空白   StringsToHexBytes

            VCI_CAN_OBJ[] buffer = new VCI_CAN_OBJ[10];
            string id = stringcmd.Substring(7, 3);// 从站地址
            buffer[0].ID = Convert.ToUInt32(id, 16);//从站id
            buffer[0].SendType = 1;//发送帧类型。=0时为正常发送(发送失败会自动重发,重发超时时间为4秒, 4秒内没有发出则取消);=1时为单次发送
            buffer[0].DataLen = buffercmd[0];//数据长度 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节。

            buffer[0].Data[0] = buffercmd[5];
            buffer[0].Data[1] = buffercmd[6];
            buffer[0].Data[2] = buffercmd[7];
            buffer[0].Data[3] = buffercmd[8];
            buffer[0].Data[4] = buffercmd[9];
            buffer[0].Data[5] = buffercmd[10];
            buffer[0].Data[6] = buffercmd[11];
            buffer[0].Data[7] = buffercmd[12];

            Int32 ret = set_Send(VCI_USBCAN2, 0, 0, ref buffer[0], 1);// 发1帧



            //byte[] buff = SendAndReceive(buffer, stringcmd);//  收发报文

            //if (buff == null) throw new Exception("ACK 未应答。。。");

            //if (buff != null)
            //{
            //    string str = help_String.BytesToHexStrings(buff);
            //    return str;
            //}
            return null;// 发送后未接收





        }

        //public unsafe object RXs()//  VCI_CAN_OBJ  //CAN帧参数
        //{
        //    //throw new NotImplementedException();

        //    // 缓存区可用帧数=============================
        //    uint i = VCI_GetReceiveNum(Help_USB_CAN.VCI_USBCAN2, 0, 0);// can1
        //    if (i > 0)// CAN1接收帧数
        //    {
        //        uint CAN1 = 0;
        //        VCI_CAN_OBJ[] obj = new VCI_CAN_OBJ[2000];// 创新科技CAN分析仪最大支持2000帧接收
        //        i = VCI_get接收(4, 0, CAN1, ref obj[0], 1, 0);//  注意 CAN1  通道

        //        #region 取一帧
        //        //=================================================
        //        byte[] bytes = new byte[13];
        //        bytes[0] = obj[0].DataLen;   //obj[0].
        //        uint id = obj[0].ID; //       帧 id
        //        bytes[1] = (byte)(id >> 24);
        //        bytes[2] = (byte)(id >> 16);
        //        bytes[3] = (byte)(id >> 8);
        //        bytes[4] = (byte)(id & 0xff);

        //        fixed (VCI_CAN_OBJ* p_obj = &obj[0])// 8字节    第一帧
        //        {
        //            bytes[5] = p_obj->Data[0];
        //            bytes[6] = p_obj->Data[1];
        //            bytes[7] = p_obj->Data[2];
        //            bytes[8] = p_obj->Data[3];
        //            bytes[9] = p_obj->Data[4];
        //            bytes[10] = p_obj->Data[5];
        //            bytes[11] = p_obj->Data[6];
        //            bytes[12] = p_obj->Data[7];
        //        }
        //        return bytes;

        //        #endregion
        //        //return obj;
        //    }
        //    return null;
        //}

        //public unsafe object RXs()//  VCI_CAN_OBJ  //CAN帧参数
        //{// CAN1 接收

        //    //throw new NotImplementedException();

        //    // 缓存区可用帧数=============================
        //    //Help_Delay.delayTime(0.005);// usb大概3~5ms
        //    int i = VCI_GetReceiveNum(Help_USB_CAN.VCI_USBCAN2, CAN_inD, CAN1);// can1
        //    if (i > 0)// CAN1接收帧数
        //    {
        //        VCI_CAN_OBJ[] obj = new VCI_CAN_OBJ[2000];// 创新科技CAN分析仪最大支持2000帧接收,间隔5ms以上
        //        i = VCI_get接收(4, 0, CAN1, ref obj[0], 2000, 50);//  注意 CAN1  通道

        //        #region 取一帧      【1   4    8】
        //        //=================================================
        //        //byte[] bytes = new byte[13];
        //        //bytes[0] = obj[0].DataLen;   //  【1】有效字节
        //        //uint id = obj[0].ID; //     帧 id【4】帧id
        //        //bytes[1] = (byte)(id >> 24);
        //        //bytes[2] = (byte)(id >> 16);
        //        //bytes[3] = (byte)(id >> 8);
        //        //bytes[4] = (byte)(id & 0xff);

        //        //fixed (VCI_CAN_OBJ* p_obj = &obj[0])// 8字节    第一帧
        //        //{
        //        //    bytes[5] = p_obj->Data[0];//  【8】包数据
        //        //    bytes[6] = p_obj->Data[1];
        //        //    bytes[7] = p_obj->Data[2];
        //        //    bytes[8] = p_obj->Data[3];
        //        //    bytes[9] = p_obj->Data[4];
        //        //    bytes[10] = p_obj->Data[5];
        //        //    bytes[11] = p_obj->Data[6];
        //        //    bytes[12] = p_obj->Data[7];
        //        //}
        //        //return bytes;

        //        #endregion
        //        return obj;
        //    }
        //    return null;
        //}
        //public unsafe object TXs(string stringcmd)// "04000006014000200000000000"
        //{//被CanOpen调用

        //    //throw new NotImplementedException();

        //    stringcmd.Replace(" ", "");//去除空白
        //    byte[] buffercmd = help_String.StringsToHexBytes(stringcmd);//准备报文  //去除空白   StringsToHexBytes

        //    VCI_CAN_OBJ[] buffer = new VCI_CAN_OBJ[10];
        //    string id = stringcmd.Substring(2, 8);// 从站地址  00000601
        //    buffer[0].ID = Convert.ToUInt32(id, 16);//从站id
        //    // 重发功能 0开,1关
        //    buffer[0].SendType = 0;//0(4秒内有重发)  1只发单次
        //    buffer[0].DataLen = buffercmd[0];//数据长度 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节。

        //    buffer[0].Data[0] = buffercmd[5];// byte8
        //    buffer[0].Data[1] = buffercmd[6];
        //    buffer[0].Data[2] = buffercmd[7];
        //    buffer[0].Data[3] = buffercmd[8];
        //    buffer[0].Data[4] = buffercmd[9];
        //    buffer[0].Data[5] = buffercmd[10];
        //    buffer[0].Data[6] = buffercmd[11];
        //    buffer[0].Data[7] = buffercmd[12];

        //    Int32 ret = VCI_set发送(Help_USB_CAN.VCI_USBCAN2, 0, CAN1, ref buffer[0], 1);// 库函数(发送TXs)
        //    return ret;
        //}

        //public int Close()
        //{
        //    //throw new NotImplementedException();
        //    return (int)set_Close((UInt32)CAN设备类型.VCI_USBCAN2, CAN_inD);
        //}

        public bool sendAndReceive<T>(string cmd, ref T t)
        {
            throw new NotImplementedException();
        }




        #endregion

    }


    #endregion




}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/163672.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Synchronized 关键字的底层原理

目录 synchronized 同步语句块的情况 synchronized 修饰方法的的情况 synchronized 关键字底层原理属于JVM 层面 synchronized 同步语句块的情况 public class SynchronizedDemo {public void method() {synchronized (this) {System.out.println("synchronized 代码块…

Alien Skin Exposure2024免费版图片颜色滤镜插件

Alien Skin Exposure一款非常专业的图片后期处理软件&#xff0c;内含500多种照片滤镜。是一款图片后期处理功能非常强大的软件。这款软件可以对图片的后期效果做很好的处理。 打开Alien Skin Exposure软件&#xff0c;会显示下面这个界面&#xff0c;如图1. ExposureX8win-安…

原型网络Prototypical Network的python代码逐行解释,新手小白也可学会!!-----系列7(承接系列6)

文章目录 前言一、原始代码---保存原型点,加载原型点二、代码逐行解释 前言 此部分为原型网络的两个函数&#xff0c;分别为保存原型点函数和加载原型点函数&#xff0c;与之前的系列相承接。 一、原始代码—保存原型点,加载原型点 def save_center(self,path):datas []for …

黔院长 | 为什么要调经络?原来通经络对人体健康如此重要!

人体的组成较为复杂&#xff0c;在外有皮肤、毛发&#xff1b;在内有经络、五脏&#xff1b;其他还有我们看不到的精气、津液等等&#xff0c;也因此人体会生各种各样的疾病。 为什么说经络畅通对人体健康如此重要&#xff1f;身体内外始终是一个统一的整体&#xff0c;内外之间…

2023全球边缘计算大会深圳站-核心PPT资料下载

一、峰会简介 边缘计算&#xff0c;是指在靠近物或数据源头的一侧&#xff0c;采用网络、计算、存储、应用核心能力为一体的开放平台&#xff0c;就近提供最近端服务。其应用程序在边缘侧发起&#xff0c;产生更快的网络服务响应&#xff0c;满足行业在实时业务、应用智能、安…

原型网络Prototypical Network的python代码逐行解释,新手小白也可学会!!-----系列8

文章目录 前言一、原始代码二、对每一行代码的解释&#xff1a;总结 前言 这是该系列原型网络的最后一段代码及其详细解释&#xff0c;感谢各位的阅读&#xff01; 一、原始代码 if __name__ __main__:##载入数据labels_trainData, labels_testData load_data() # labels_…

【AI】行业消息精选和分析(23-11-19)

行业动态 1、对标GPTs&#xff0c;微软连夜发布100多项更新&#xff01;微软CEO&#xff1a;Copilot时代来了 2、英伟达联手微软推出AI代工服务 3、全新雅虎搜索将于 2024 年上线&#xff0c;未来还会推出更多 AI 和高级功能 4、Instagram 推出定制 AI 贴纸和滤镜功能&#xff…

适用于全部安卓手机的 5 大免费 Android 数据恢复

您是否面临这样一种情况&#xff0c;即在Android设备上丢失了一些重要文件&#xff0c;但不知道应该选择哪种Android数据恢复来取回它们&#xff1f; 如果您以前从未备份过Android数据&#xff0c;则很难解决问题。 本文将介绍排名前5位的免费Android数据恢复软件。 您可以获…

【教3妹学编程-算法题】三个无重叠子数组的最大和

2哥 : 3妹&#xff0c;咋啦&#xff1f;一副苦大仇深的样子&#xff1f; 3妹&#xff1a;不开心呀不开心&#xff0c;羽生结弦宣布离婚。 2哥 : 羽生什么&#xff1f; 3妹&#xff1a;羽生结弦&#xff01; 2哥 : 什么结弦&#xff1f; 3妹&#xff1a;羽生结弦&#xff01;&am…

理论与实践相结合之Cisco Packet Tracer网络模拟器安装教程

简介 Packet Tracer是由思科设计的跨平台可视化仿真工具&#xff0c;它允许用户创建网络拓扑以模仿计算机网络和使用命令行界面来模拟配置思科路由器和交换机。Packet Tracer的用户界面为拖放式&#xff0c;允许用户根据自己的需要添加和删除模拟的网络设备。 Packet Tracer很…

安卓手机投屏到电视,跨品牌、跨地域同样可以实现!

在手机网页上看到的视频&#xff0c;也可以投屏到电视上看&#xff01; 长时间使用手机&#xff0c;难免脖子会酸。这时候&#xff0c;如果你将手机屏幕投屏到大电视屏幕&#xff0c;可以减缓脖子的压力&#xff0c;而且大屏的视觉体验更爽。 假设你有一台安卓手机&#xff0c;…

odoo17前端js框架的演化

odoo17发布了&#xff0c;从界面上看&#xff0c;变化还是很明显的&#xff0c;比16更漂亮了&#xff0c;本来以为源码不会发生太大的变化&#xff0c;结果仔细一瞧&#xff0c;变化也不小。 1、打包好的文件数量和大小发生了变化 打包好的文件从两个变成了一个&#xff0c;在…

在excel中设置图表的标题

已经在excel做好了一个图&#xff0c;默认是没有标题的&#xff1a; 现在来设置一个标题。 双击图表&#xff0c;进入编辑状态&#xff1a; 右键&#xff0c;选择“插入标题”&#xff1a; 输入标题&#xff1a;

0基础编程教学,编程零基础该学什么,中文编程工具下载

0基础编程教学&#xff0c;编程零基础该学什么&#xff0c;中文编程工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;象…

vscode pandas无法使用

一、代码内容 import csv csv_reader csv.reader(open("data.csv")) for row in csv_reader:print(row) print(row[2]) 二、错误提示 ModuleNotFoundError: No module named pandas 三、安装pandas 然后我安装pandas&#xff0c;因为我的python的版本是python …

Dynamsoft Barcode Reader新框架将医疗视觉提升到新水平

Dynamsoft Vision 框架将医疗保健领域的计算机视觉提升到新的水平 引入图像捕获、内容理解、结果解析和交互式工作流程的聚合 SDK&#xff0c;以简化复杂的流程。 温哥华 – 2023 年 7 月 17 日 – Dynamsoft™ 发布了 Dynamsoft Barcode Reader SDK C Edition v10.0.0。更新…

Kotlin 知识体系

Kotlin 知识体系 1、Kotlin 文档2、Kotlin 基础3、桌面应用程序4、Android 与 iOS 应用程序 1、Kotlin 文档 Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复…

基于STM32单片机数字电压表自动切换量程及源程序

一、系统方案 1、本设计采用这STM32单片机作为主控器。 2、液晶1602显示。 3、内部ADC采集电压0-12V&#xff0c;自动切换档位。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 u8 i; u16 a,b,c,d; u16 adcx; float adc; unsigned char datas…

(免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对线上兼职等问题&#xff0c;对线上兼职进行…

后端技术知识点内容-全部内容-面试宝典-后端面试知识点

文章目录 -2 flink-1 linux of viewlinux查看占用cup最高的10个进程的命令&#xff1b; 〇、分布式锁 & 分布式事务0-1分布式锁--包含CAP理论模型概述分布式锁&#xff1a;分布式锁应该具备哪些条件&#xff1a;分布式锁的业务场景&#xff1a; 分布式锁的实现方式有&#…
最新文章