3

我已经尝试了各种方法的许多不同组合来编组这个调用。这是一个 DLL,它返回一个指向结构数组的指针的指针。像 debugPort 这样的类型实际上是枚举。

/**
* \struct debugConnectParameters 
* \brief Get device characterization and specify connection parameters through ST-LINK interface. 
*/ 
typedef struct debugConnectParameters { 
    debugPort dbgPort;        /**< Select the type of debug interface #debugPort. */ 
    int index;                /**< Select one of the debug ports connected. */ 
    char serialNumber[33];    /**< ST-LINK serial number. */ 
    char firmwareVersion[20]; /**< Firmware version. */ 
    char targetVoltage[5];    /**< Operate voltage. */ 
    int accessPortNumber;     /**< Number of available access port. */ 
    int accessPort;           /**< Select access port controller. */ 
    debugConnectMode connectionMode; /**< Select the debug CONNECT mode #debugConnectMode. */ 
    debugResetMode resetMode; /**< Select the debug RESET mode #debugResetMode. */ 
    int isOldFirmware;        /**< Check Old ST-LINK firmware version. */ 
    frequencies freq;         /**< Supported frequencies #frequencies. */ 
    int frequency;            /**< Select specific frequency. */ 
    int isBridge;             /**< Indicates if it's Bridge device or not. */ 
    int shared;               /**< Select connection type, if it's shared, use ST-LINK Server. */ 
} debugConnectParameters;

int getStLinkList(debugConnectParameters** stLinkList, int shared);
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public unsafe struct debugConnectParameters
    {
        debugPort dbgPort;                  /**< Select the type of debug interface #debugPort. */
        int index;                          /**< Select one of the debug ports connected. */
        fixed char serialNumber[33];        /**< ST-LINK serial number. */
        fixed char firmwareVersion[20];     /**< Firmware version. */
        fixed char targetVoltage[5];        /**< Operate voltage. */
        int accessPortNumber;               /**< Number of available access port. */
        int accessPort;                     /**< Select access port controller. */
        debugConnectMode connectionMode;    /**< Select the debug CONNECT mode #debugConnectMode. */
        debugResetMode resetMode;           /**< Select the debug RESET mode #debugResetMode. */
        int isOldFirmware;                  /**< Check Old ST-LINK firmware version. */
        frequencies freq;                   /**< Supported frequencies #frequencies. */
        int frequency;                      /**< Select specific frequency. */
        int isBridge;                       /**< Indicates if it's Bridge device or not. */
        int shared;                         /**< Select connection type, if it's shared, use ST-LINK Server. */
    }
    [DllImport(dllPath + "CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public unsafe extern static int getStLinkList(
        debugConnectParameters** stLinkList,
        int shared
        );

我尝试替换使用“out”和“ref”选项。我试图找到它喜欢的 IntPtr 版本。我不断收到:System.AccessViolationException。我已经联系 STMicroelectronics 关于如何与这个 DLL 接口,但到目前为止他们没有任何帮助。DLL 中的其余调用非常简单,但我必须让这个调用开始,因为它是关于实际连接的 JTAG 设备的信息。

更新(20 年 6 月 12 日)以添加实际的调用函数,现在调用函数将结构从非托管结构复制到托管结构。但是对 getStLinkList() 的调用仍然不起作用。

        public unsafe static int GetDeviceList(ref debugConnectParameters[] debugParams, int maxCount)
        {
            IntPtr unManagedListPtr = Marshal.AllocHGlobal(sizeof(debugConnectParameters*));
            IntPtr *unManagedListPtrPtr = &unManagedListPtr;
            int count = getStLinkList((debugConnectParameters**)unManagedListPtrPtr, 0);
            IntPtr copyPtr = unManagedListPtr;
            if (count > maxCount) count = maxCount;
            for (int i = 0; i < count; i++)
            {
                debugParams[i] = (debugConnectParameters)Marshal.PtrToStructure(copyPtr, typeof(debugConnectParameters));
                copyPtr += sizeof(debugConnectParameters);
            }
            Marshal.FreeHGlobal(unManagedListPtr);
            return (count);
        }

我也尝试了这些更改,但没有运气。我仍然看到访问冲突。尝试读取或写入受保护的内存。


    [DllImport(dllPath + "CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        unsafe private static extern int getStLinkList(
            ref IntPtr stLinkList,
            int shared
            );
    unsafe public static int GetDeviceList(List<debugConnectParameters> list)
    {
        IntPtr unManagedListPtr = Marshal.AllocHGlobal(sizeof(debugConnectParameters*));
        IntPtr copyPtr = unManagedListPtr;

            int count = getStLinkList(ref unManagedListPtr, 0);

            if (count > 10) count = 10;
            for (int i = 0; i < count; i++)
            {
                debugConnectParameters parameter = (debugConnectParameters)Marshal.PtrToStructure(copyPtr, typeof(debugConnectParameters));
                list.Add(parameter);
                copyPtr += sizeof(debugConnectParameters);
            }

            Marshal.FreeHGlobal(unManagedListPtr);
            return (count);
    }
4

1 回答 1

4

getStLinkList在调用“CubeProgrammer_API.dll”库的函数方面,有两件事对我们不利。如果不纠正它们,库将无法工作,即使是 C++ 也是如此。

首先,在 STM32CubeProgrammer 安装的api/lib文件夹中找到的该库的依赖项并非全部针对 x64 编译。bin文件夹中的版本是您希望在运行时可用的库。我通过在项目调试设置中将工作目录设置为该目录来完成此操作。这是通过检查api/libbin文件夹中每个 DLL 的目标机器来验证的。

其次,“CubeProgrammer_API.dll”需要在调用前getStLinkList通过setLoadersPathsetDisplayCallbacks函数进行初始化。第一个函数必须提供“Flash Loader”的路径,在我的例子中是bin/FlashLoader。该setDisplayCallbacks函数采用三个函数指针的结构。

下面的示例可能不是类型编组的最佳示例,但它将说明该过程。

public static class CubeProgrammerApi
{
    public enum DebugConnectionMode
    {
        NormalMode = 0,
        HotplugMode = 1,
        UnderResetMode = 2,
        PreResetMode = 3
    }
    
    public enum DebugResetMode
    {
        SoftwareReset = 0,
        HardwareReset = 1,
        CoreReset = 2
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class Frequencies
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        uint[] JtagFrequency;
        uint JTagFrequencyNumber;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        uint[] SwdFrequency;
        uint SwdFrequencyNumber;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class DebugConnectParameters
    {
        DebugPort DebugPort;
        public int Index;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
        public string SerialNumber;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string FirmwareVersion;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
        public string TargetVoltage;
        public int AccesPortNumber;
        public int AccessPort;
        public DebugConnectionMode connectionMode;
        public DebugResetMode resetMode;
        public bool IsOldFirmware;
        public Frequencies Freqencies;
        public int Frequency;
        public bool IsBridge;
        public int Shared;
    }
    
    public delegate void LogMessageReceived(int messageType, [MarshalAs(UnmanagedType.LPWStr)] string message);
    public delegate void InitProgressBar();
    public delegate void ProgressBarUpdateReceived(int currentProgress, int total);

    internal static class NativeMethods
    {
        public struct DisplayCallbacks
        {
            public InitProgressBar initProgressBar;
            public LogMessageReceived logMessage;
            public ProgressBarUpdateReceived loadBar;
        }

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "setLoadersPath")]
        internal static extern void SetLoadersPath(string path);

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "setDisplayCallbacks")]
        internal static extern void SetDisplayCallbacks(ref DisplayCallbacks callbacks);

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getStLinkList")]
        internal static extern int GetStLinkList(IntPtr stLinkList, uint shared);

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void deleteInterfaceList();

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "reset")]
        internal static extern int Reset([MarshalAs(UnmanagedType.U4)] DebugResetMode rstMode);
    }

    public static void SetLoadersPath(string path)
    {
        NativeMethods.SetLoadersPath(path);
    }

    public static void SetDisplayCallbacks(InitProgressBar initProgressBar, LogMessageReceived messageReceived, ProgressBarUpdateReceived progressBarUpdate)
    {
        NativeMethods.DisplayCallbacks callbacksHandle;

        callbacksHandle.initProgressBar = initProgressBar;
        callbacksHandle.logMessage = messageReceived;
        callbacksHandle.loadBar = progressBarUpdate;

        NativeMethods.SetDisplayCallbacks(ref callbacksHandle);
    }

    public static IList<DebugConnectParameters> GetStLinkProgrammers(bool shared = false)
    {
        var listPtr = Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>());
        var parametersList = new List<DebugConnectParameters>();

        try
        {
            var size = Marshal.SizeOf<DebugConnectParameters>();
            var numberOfItems = NativeMethods.GetStLinkList(listPtr, shared ? 1U : 0U);
            var listDereference = Marshal.PtrToStructure<IntPtr>(listPtr);

            for (var i = 0; i < numberOfItems; i++)
            {
                var currentItem = Marshal.PtrToStructure<DebugConnectParameters>(listDereference + (i * size));

                parametersList.Add(currentItem);
            }

            NativeMethods.deleteInterfaceList();
        }
        finally
        {
            Marshal.FreeHGlobal(listPtr);
        }

        return parametersList;
    }

    public static void FreeStLinkProgrammers()
    {
        NativeMethods.deleteInterfaceList();
    }
}

主要:

class Program
    {
        static void Main(string[] args)
        {
            CubeProgrammerApi.SetLoadersPath(@"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\FlashLoader");
            CubeProgrammerApi.SetDisplayCallbacks(InitProgressBar, ReceiveMessage, ProgressBarUpdate);
            var stLinkList = CubeProgrammerApi.GetStLinkProgrammers();

            foreach (var stlink in stLinkList)
            {
                Console.WriteLine("{0} {1}", stlink.Index, stlink.SerialNumber);
            }

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();

            CubeProgrammerApi.FreeStLinkProgrammers();
        }

        static void ReceiveMessage(int messgaeType, string message)
        {

        }

        static void InitProgressBar()
        {

        }

        static void ProgressBarUpdate(int currentProgress, int total)
        {

        }
    }

这将输出以下内容,并附加两个调试器,分别是 STLink V3 和 STLink V2。这应该会让您走得更远,以发现要使用的正确类型。

0 002F001D3038511834333935
1 34FF6D065250343847110943
Press ENTER to exit
于 2020-07-15T21:24:36.233 回答