//*************************************************************************************** // Description: Class for accessing the OpenBLT shared library in C#. // File Name: openblt.cs // //--------------------------------------------------------------------------------------- // C O P Y R I G H T //--------------------------------------------------------------------------------------- // Copyright (c) 2021 by Feaser http://www.feaser.com All rights reserved // // This software has been carefully tested, but is not guaranteed for any particular // purpose. The author does not offer any warranties and does not guarantee the accuracy, // adequacy, or completeness of the software and is not responsible for any errors or // omissions or the results obtained from use of the software. // //--------------------------------------------------------------------------------------- // L I C E N S E //--------------------------------------------------------------------------------------- // This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or // modify it under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) any later // version. // // OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the GNU General Public License for more details. // // You have received a copy of the GNU General Public License along with OpenBLT. It // should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. // //*************************************************************************************** using System; using System.Runtime.InteropServices; using System.Diagnostics; namespace OpenBLT { /// /// C# wrapper class for the OpenBLT host library called LibOpenBLT. For more /// information about LibOpenBLT, refer to: /// https://www.feaser.com/openblt/doku.php?id=manual:libopenblt /// /// /// Note that under Microsoft Windows, the LibOpenBLT shared library (libopenblt.dll) /// is 32-bit. For this reason, whatever project uses this wrapper class needs to /// be built as a 32-bit application. /// /// To configure this, go to your project's properties in Microsoft Visual Studio. /// In the "Build" settings, set "Platform target" to "x86". /// public static class Lib { /// /// The name of the shared library file. Luckily there is no need to specify the /// file extension (.dll on Windows and .so on Linux), so this wrapper class /// should be cross-platform. /// /// /// Note that this file and the other related run-time library files must be /// located either someone accessible on the searchpath or in the same /// directory as your application's executable. /// For an overview of the LibOpenBLT run-time library files, refer to: /// https://www.feaser.com/openblt/doku.php?id=manual:libopenblt#run-time_libraries /// private const String LIBNAME = "libopenblt"; /// /// Function return value for when everything went okay. /// public const UInt32 RESULT_OK = 0; /// /// Function return value for when a generic error occured. /// public const UInt32 RESULT_ERROR_GENERIC = 1; /// /// Wrapper for the version module of LibOpenBLT. /// public static class Version { [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltVersionGetNumber(); /// /// Obtains the version number of the library as an integer. The number has two /// digits for major-, minor-, and patch-version.Version 1.05.12 would for /// example return 10512. /// /// Library version number as an integer. /// /// /// Console.WriteLine("LibOpenBLT version number: {0}", OpenBLT.Lib.Version.GetNumber()); /// /// public static UInt32 GetNumber() { return BltVersionGetNumber(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr BltVersionGetString(); /// /// Obtains the version number of the library as a null-terminated string. Version /// 1.05.12 would for example return "1.05.12". /// /// Library version number as a string. /// /// /// Console.WriteLine("LibOpenBLT version string: {0}", OpenBLT.Lib.Version.GetString()); /// /// public static String GetString() { return Marshal.PtrToStringAnsi(BltVersionGetString()); } } /// /// Wrapper for the session module of LibOpenBLT. /// public static class Session { /// /// XCP protocol version 1.0. XCP is a universal measurement and calibration /// communication protocol. It contains functionality for reading, programming, /// and erasing (non-volatile) memory making it a good fit for bootloader /// purposes. /// private const UInt32 SESSION_XCP_V10 = 0; /// /// Transport layer for the XCP v1.0 protocol that uses RS-232 serial /// communication for data exchange. /// private const UInt32 TRANSPORT_XCP_V10_RS232 = 0; /// /// Transport layer for the XCP v1.0 protocol that uses Controller Area Network /// (CAN) for data exchange. /// private const UInt32 TRANSPORT_XCP_V10_CAN = 1; /// /// Transport layer for the XCP v1.0 protocol that uses USB Bulk for data /// exchange. /// private const UInt32 TRANSPORT_XCP_V10_USB = 2; /// /// Transport layer for the XCP v1.0 protocol that uses TCP/IP for data /// exchange. /// private const UInt32 TRANSPORT_XCP_V10_NET = 3; /// /// Structure layout of the XCP version 1.0 session settings. /// public struct SessionSettingsXcpV10 { /// /// Command response timeout in milliseconds. /// public UInt16 timeoutT1; /// /// Start programming timeout in milliseconds. /// public UInt16 timeoutT3; /// /// Erase memory timeout in milliseconds. /// public UInt16 timeoutT4; /// /// Program memory and reset timeout in milliseconds. /// public UInt16 timeoutT5; /// /// Connect response timeout in milliseconds. /// public UInt16 timeoutT6; /// /// Busy wait timer timeout in milliseonds. /// public UInt16 timeoutT7; /// /// Seed/key algorithm library filename. /// public String seedKeyFile; /// /// Connection mode parameter in XCP connect command. /// public Byte connectMode; } /// /// Unmanaged structure layout of the XCP version 1.0 session settings. /// /// /// Only used internally when calling the API function inside the DLL. /// [StructLayout(LayoutKind.Sequential)] private struct SessionSettingsXcpV10Unmanaged { public UInt16 timeoutT1; public UInt16 timeoutT3; public UInt16 timeoutT4; public UInt16 timeoutT5; public UInt16 timeoutT6; public UInt16 timeoutT7; public IntPtr seedKeyFile; public Byte connectMode; } /// /// Structure layout of the XCP version 1.0 RS232 transport layer settings. /// /// /// The portName field is platform dependent. On Linux based systems this should be /// the filename of the tty-device, such as "/dev/tty0". On Windows based systems /// it should be the name of the COM-port, such as "COM1". /// public struct TransportSettingsXcpV10Rs232 { /// /// Communication port name such as /dev/tty0. /// public String portName; /// /// Communication speed in bits/sec. /// public UInt32 baudrate; } /// /// Unmanaged structure layout of the XCP version 1.0 RS232 transport layer settings. /// /// /// Only used internally when calling the API function inside the DLL. /// [StructLayout(LayoutKind.Sequential)] private struct TransportSettingsXcpV10Rs232Unmanaged { public IntPtr portName; public UInt32 baudrate; } /// /// Structure layout of the XCP version 1.0 CAN transport layer settings. /// /// /// The deviceName field is platform dependent.On Linux based systems this should /// be the socketCAN interface name such as "can0". The terminal command "ip addr" /// can be issued to view a list of interfaces that are up and available. Under /// Linux it is assumed that the socketCAN interface is already configured on the /// system, before using the OpenBLT library.When baudrate is configured when /// bringing up the system, so the baudrate field in this structure is don't care /// when using the library on a Linux was system. On Windows based systems, the /// device name is a name that is pre-defined by this library for the supported /// CAN adapters. The device name should be one of the following: "peak_pcanusb", /// "kvaser_leaflight", or "lawicel_canusb". Field use extended is a boolean /// field.When set to 0, the specified transmitId and receiveId are assumed to /// be 11-bit standard CAN identifier. If the field is True, these identifiers /// are assumed to be 29-bit extended CAN identifiers. /// public struct TransportSettingsXcpV10Can { /// /// Device name such as can0, peak_pcanusb etc. /// public String deviceName; /// /// Channel on the device to use. /// public UInt32 deviceChannel; /// /// Communication speed in bits/sec. /// public UInt32 baudrate; /// /// Transmit CAN identifier. /// public UInt32 transmitId; /// /// Receive CAN identifier. /// public UInt32 receiveId; /// /// Boolean to configure 29-bit CAN identifiers. /// public Boolean useExtended; } /// /// Unmanaged structure layout of the XCP version 1.0 CAN transport layer settings. /// /// /// Only used internally when calling the API function inside the DLL. /// [StructLayout(LayoutKind.Sequential)] private struct TransportSettingsXcpV10CanUnmanaged { public IntPtr deviceName; public UInt32 deviceChannel; public UInt32 baudrate; public UInt32 transmitId; public UInt32 receiveId; public UInt32 useExtended; } /// /// Structure layout of the XCP version 1.0 NET transport layer settings. /// /// /// The address field can be set to either the IP address or the hostname, such /// as "192.168.178.23" or "mymicro.mydomain.com". The port should be set to the /// TCP port number that the bootloader target listens on. /// public struct TransportSettingsXcpV10Net { /// /// Target IP-address or hostname on the network. /// public String address; /// /// TCP port to use. /// public UInt16 port; } /// /// Unmanaged structure layout of the XCP version 1.0 TCP/IP transport layer settings. /// /// /// Only used internally when calling the API function inside the DLL. /// [StructLayout(LayoutKind.Sequential)] private struct TransportSettingsXcpV10NetUnmanaged { public IntPtr address; public UInt16 port; } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltSessionInit(UInt32 sessionType, IntPtr sessionSettings, UInt32 transportType, IntPtr transportSettings); /// /// Initializes the firmware update session for the XCP v1.0 communication /// protocol and RS232 as the transport layer. This function is typically /// called once at the start of the firmware update. /// /// XCP V1.0 protocol settings /// RS232 transport layer settings /// /// /// OpenBLT.Lib.Session.SessionSettingsXcpV10 sessionSettings; /// sessionSettings.timeoutT1 = 1000; /// sessionSettings.timeoutT3 = 2000; /// sessionSettings.timeoutT4 = 10000; /// sessionSettings.timeoutT5 = 1000; /// sessionSettings.timeoutT6 = 50; /// sessionSettings.timeoutT7 = 2000; /// sessionSettings.seedKeyFile = ""; /// sessionSettings.connectMode = 0; /// /// OpenBLT.Lib.Session.TransportSettingsXcpV10Rs232 transportSettings; /// transportSettings.portName = "COM8"; /// transportSettings.baudrate = 57600; /// /// OpenBLT.Lib.Session.Init(sessionSettings, transportSettings); /// /// public static void Init(SessionSettingsXcpV10 sessionSettings, TransportSettingsXcpV10Rs232 transportSettings) { // Copy the managed session settings to an unmanaged structure. SessionSettingsXcpV10Unmanaged sessionSettingsUnmanaged; sessionSettingsUnmanaged.timeoutT1 = sessionSettings.timeoutT1; sessionSettingsUnmanaged.timeoutT3 = sessionSettings.timeoutT3; sessionSettingsUnmanaged.timeoutT4 = sessionSettings.timeoutT4; sessionSettingsUnmanaged.timeoutT5 = sessionSettings.timeoutT5; sessionSettingsUnmanaged.timeoutT6 = sessionSettings.timeoutT6; sessionSettingsUnmanaged.timeoutT7 = sessionSettings.timeoutT7; // Convert string to unmanged string. sessionSettingsUnmanaged.seedKeyFile = (IntPtr)Marshal.StringToHGlobalAnsi(sessionSettings.seedKeyFile); sessionSettingsUnmanaged.connectMode = sessionSettings.connectMode; // Copy the managed transport settings to an unmanaged structure. TransportSettingsXcpV10Rs232Unmanaged transportSettingsUnmanaged; // Convert string to unmanaged string. transportSettingsUnmanaged.portName = (IntPtr)Marshal.StringToHGlobalAnsi(transportSettings.portName); transportSettingsUnmanaged.baudrate = transportSettings.baudrate; // The structures are now formatted to be converted to unmanaged memory. Start by allocating // memory on the heap for this. IntPtr sessionSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sessionSettingsUnmanaged)); IntPtr transportSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(transportSettingsUnmanaged)); // Assert the heap allocations. Debug.Assert(sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero); Debug.Assert(transportSettingsUnmanaged.portName != IntPtr.Zero); Debug.Assert(sessionSettingsUnmanagedPtr != IntPtr.Zero); Debug.Assert(transportSettingsUnmanagedPtr != IntPtr.Zero); // Only continue if all the heap allocations were successful. if ((sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero) && (transportSettingsUnmanaged.portName != IntPtr.Zero) && (sessionSettingsUnmanagedPtr != IntPtr.Zero) && (transportSettingsUnmanagedPtr != IntPtr.Zero)) { // Copy the structures to unmanaged memory. Marshal.StructureToPtr(sessionSettingsUnmanaged, sessionSettingsUnmanagedPtr, false); Marshal.StructureToPtr(transportSettingsUnmanaged, transportSettingsUnmanagedPtr, false); // Call the API function inside the DLL. BltSessionInit(SESSION_XCP_V10, sessionSettingsUnmanagedPtr, TRANSPORT_XCP_V10_RS232, transportSettingsUnmanagedPtr); // Free memory allocated on the heap. Marshal.FreeHGlobal(transportSettingsUnmanagedPtr); Marshal.FreeHGlobal(sessionSettingsUnmanagedPtr); Marshal.FreeHGlobal(transportSettingsUnmanaged.portName); Marshal.FreeHGlobal(sessionSettingsUnmanaged.seedKeyFile); } } /// /// Initializes the firmware update session for the XCP v1.0 communication /// protocol and CAN as the transport layer. This function is typically /// called once at the start of the firmware update. /// /// XCP V1.0 protocol settings /// CAN transport layer settings /// /// /// OpenBLT.Lib.Session.SessionSettingsXcpV10 sessionSettings; /// sessionSettings.timeoutT1 = 1000; /// sessionSettings.timeoutT3 = 2000; /// sessionSettings.timeoutT4 = 10000; /// sessionSettings.timeoutT5 = 1000; /// sessionSettings.timeoutT6 = 50; /// sessionSettings.timeoutT7 = 2000; /// sessionSettings.seedKeyFile = ""; /// sessionSettings.connectMode = 0; /// /// OpenBLT.Lib.Session.TransportSettingsXcpV10Can transportSettings; /// transportSettings.deviceName = "peak_pcanusb"; /// transportSettings.deviceChannel = 0; /// transportSettings.baudrate = 500000; /// transportSettings.transmitId = 0x667; /// transportSettings.receiveId = 0x7E1; /// transportSettings.useExtended = false; /// /// OpenBLT.Lib.Session.Init(sessionSettings, transportSettings); /// /// public static void Init(SessionSettingsXcpV10 sessionSettings, TransportSettingsXcpV10Can transportSettings) { // Copy the managed session settings to an unmanaged structure. SessionSettingsXcpV10Unmanaged sessionSettingsUnmanaged; sessionSettingsUnmanaged.timeoutT1 = sessionSettings.timeoutT1; sessionSettingsUnmanaged.timeoutT3 = sessionSettings.timeoutT3; sessionSettingsUnmanaged.timeoutT4 = sessionSettings.timeoutT4; sessionSettingsUnmanaged.timeoutT5 = sessionSettings.timeoutT5; sessionSettingsUnmanaged.timeoutT6 = sessionSettings.timeoutT6; sessionSettingsUnmanaged.timeoutT7 = sessionSettings.timeoutT7; // Convert string to unmanged string. sessionSettingsUnmanaged.seedKeyFile = (IntPtr)Marshal.StringToHGlobalAnsi(sessionSettings.seedKeyFile); sessionSettingsUnmanaged.connectMode = sessionSettings.connectMode; // Copy the managed transport settings to an unmanaged structure. TransportSettingsXcpV10CanUnmanaged transportSettingsUnmanaged; // Convert string to unmanaged string. transportSettingsUnmanaged.deviceName = (IntPtr)Marshal.StringToHGlobalAnsi(transportSettings.deviceName); transportSettingsUnmanaged.deviceChannel = transportSettings.deviceChannel; transportSettingsUnmanaged.baudrate = transportSettings.baudrate; transportSettingsUnmanaged.transmitId = transportSettings.transmitId; transportSettingsUnmanaged.receiveId = transportSettings.receiveId; transportSettingsUnmanaged.useExtended = 0; if (transportSettings.useExtended) { transportSettingsUnmanaged.useExtended = 1; } // The structures are now formatted to be converted to unmanaged memory. Start by allocating // memory on the heap for this. IntPtr sessionSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sessionSettingsUnmanaged)); IntPtr transportSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(transportSettingsUnmanaged)); // Assert the heap allocations. Debug.Assert(sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero); Debug.Assert(transportSettingsUnmanaged.deviceName != IntPtr.Zero); Debug.Assert(sessionSettingsUnmanagedPtr != IntPtr.Zero); Debug.Assert(transportSettingsUnmanagedPtr != IntPtr.Zero); // Only continue if all the heap allocations were successful. if ((sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero) && (transportSettingsUnmanaged.deviceName != IntPtr.Zero) && (sessionSettingsUnmanagedPtr != IntPtr.Zero) && (transportSettingsUnmanagedPtr != IntPtr.Zero)) { // Copy the structures to unmanaged memory. Marshal.StructureToPtr(sessionSettingsUnmanaged, sessionSettingsUnmanagedPtr, false); Marshal.StructureToPtr(transportSettingsUnmanaged, transportSettingsUnmanagedPtr, false); // Call the API function inside the DLL. BltSessionInit(SESSION_XCP_V10, sessionSettingsUnmanagedPtr, TRANSPORT_XCP_V10_CAN, transportSettingsUnmanagedPtr); // Free memory allocated on the heap. Marshal.FreeHGlobal(transportSettingsUnmanagedPtr); Marshal.FreeHGlobal(sessionSettingsUnmanagedPtr); Marshal.FreeHGlobal(transportSettingsUnmanaged.deviceName); Marshal.FreeHGlobal(sessionSettingsUnmanaged.seedKeyFile); } } /// /// Initializes the firmware update session for the XCP v1.0 communication /// protocol and USB as the transport layer. This function is typically /// called once at the start of the firmware update. /// /// /// Note that the USB transport layer does not need any configuration /// settings. Therefore, this function only needs the session /// settings as a parameter. /// /// XCP V1.0 protocol settings /// /// /// OpenBLT.Lib.Session.SessionSettingsXcpV10 sessionSettings; /// sessionSettings.timeoutT1 = 1000; /// sessionSettings.timeoutT3 = 2000; /// sessionSettings.timeoutT4 = 10000; /// sessionSettings.timeoutT5 = 1000; /// sessionSettings.timeoutT6 = 50; /// sessionSettings.timeoutT7 = 2000; /// sessionSettings.seedKeyFile = ""; /// sessionSettings.connectMode = 0; /// /// OpenBLT.Lib.Session.Init(sessionSettings); /// /// public static void Init(SessionSettingsXcpV10 sessionSettings) { // Copy the managed session settings to an unmanaged structure. SessionSettingsXcpV10Unmanaged sessionSettingsUnmanaged; sessionSettingsUnmanaged.timeoutT1 = sessionSettings.timeoutT1; sessionSettingsUnmanaged.timeoutT3 = sessionSettings.timeoutT3; sessionSettingsUnmanaged.timeoutT4 = sessionSettings.timeoutT4; sessionSettingsUnmanaged.timeoutT5 = sessionSettings.timeoutT5; sessionSettingsUnmanaged.timeoutT6 = sessionSettings.timeoutT6; sessionSettingsUnmanaged.timeoutT7 = sessionSettings.timeoutT7; // Convert string to unmanged string. sessionSettingsUnmanaged.seedKeyFile = (IntPtr)Marshal.StringToHGlobalAnsi(sessionSettings.seedKeyFile); sessionSettingsUnmanaged.connectMode = sessionSettings.connectMode; // Note that the USB transport layer does not require any settings. The settings structure is // now formatted to be converted to unmanaged memory. Start by allocating memory on the heap for this. IntPtr sessionSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sessionSettingsUnmanaged)); // Assert the heap allocations. Debug.Assert(sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero); Debug.Assert(sessionSettingsUnmanagedPtr != IntPtr.Zero); // Only continue if all the heap allocations were successful. if ((sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero) && (sessionSettingsUnmanagedPtr != IntPtr.Zero)) { // Copy the structure to unmanaged memory. Marshal.StructureToPtr(sessionSettingsUnmanaged, sessionSettingsUnmanagedPtr, false); // Call the API function inside the DLL. BltSessionInit(SESSION_XCP_V10, sessionSettingsUnmanagedPtr, TRANSPORT_XCP_V10_USB, IntPtr.Zero); // Free memory allocated on the heap. Marshal.FreeHGlobal(sessionSettingsUnmanagedPtr); Marshal.FreeHGlobal(sessionSettingsUnmanaged.seedKeyFile); } } /// /// Initializes the firmware update session for the XCP v1.0 communication /// protocol and TCP/IP as the transport layer. This function is typically /// called once at the start of the firmware update. /// /// XCP V1.0 protocol settings /// TCP/IP transport layer settings /// /// /// OpenBLT.Lib.Session.SessionSettingsXcpV10 sessionSettings; /// sessionSettings.timeoutT1 = 1000; /// sessionSettings.timeoutT3 = 2000; /// sessionSettings.timeoutT4 = 10000; /// sessionSettings.timeoutT5 = 1000; /// sessionSettings.timeoutT6 = 50; /// sessionSettings.timeoutT7 = 2000; /// sessionSettings.seedKeyFile = ""; /// sessionSettings.connectMode = 0; /// /// OpenBLT.Lib.Session.TransportSettingsXcpV10Net transportSettings; /// transportSettings.address = "192.168.178.30"; /// transportSettings.port = 1000; /// /// OpenBLT.Lib.Session.Init(sessionSettings, transportSettings); /// /// public static void Init(SessionSettingsXcpV10 sessionSettings, TransportSettingsXcpV10Net transportSettings) { // Copy the managed session settings to an unmanaged structure. SessionSettingsXcpV10Unmanaged sessionSettingsUnmanaged; sessionSettingsUnmanaged.timeoutT1 = sessionSettings.timeoutT1; sessionSettingsUnmanaged.timeoutT3 = sessionSettings.timeoutT3; sessionSettingsUnmanaged.timeoutT4 = sessionSettings.timeoutT4; sessionSettingsUnmanaged.timeoutT5 = sessionSettings.timeoutT5; sessionSettingsUnmanaged.timeoutT6 = sessionSettings.timeoutT6; sessionSettingsUnmanaged.timeoutT7 = sessionSettings.timeoutT7; // Convert string to unmanged string. sessionSettingsUnmanaged.seedKeyFile = (IntPtr)Marshal.StringToHGlobalAnsi(sessionSettings.seedKeyFile); sessionSettingsUnmanaged.connectMode = sessionSettings.connectMode; // Copy the managed transport settings to an unmanaged structure. TransportSettingsXcpV10NetUnmanaged transportSettingsUnmanaged; // Convert string to unmanaged string. transportSettingsUnmanaged.address = (IntPtr)Marshal.StringToHGlobalAnsi(transportSettings.address); transportSettingsUnmanaged.port = transportSettings.port; // The structures are now formatted to be converted to unmanaged memory. Start by allocating // memory on the heap for this. IntPtr sessionSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sessionSettingsUnmanaged)); IntPtr transportSettingsUnmanagedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(transportSettingsUnmanaged)); // Assert the heap allocations. Debug.Assert(sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero); Debug.Assert(transportSettingsUnmanaged.address != IntPtr.Zero); Debug.Assert(sessionSettingsUnmanagedPtr != IntPtr.Zero); Debug.Assert(transportSettingsUnmanagedPtr != IntPtr.Zero); // Only continue if all the heap allocations were successful. if ((sessionSettingsUnmanaged.seedKeyFile != IntPtr.Zero) && (transportSettingsUnmanaged.address != IntPtr.Zero) && (sessionSettingsUnmanagedPtr != IntPtr.Zero) && (transportSettingsUnmanagedPtr != IntPtr.Zero)) { // Copy the structures to unmanaged memory. Marshal.StructureToPtr(sessionSettingsUnmanaged, sessionSettingsUnmanagedPtr, false); Marshal.StructureToPtr(transportSettingsUnmanaged, transportSettingsUnmanagedPtr, false); // Call the API function inside the DLL. BltSessionInit(SESSION_XCP_V10, sessionSettingsUnmanagedPtr, TRANSPORT_XCP_V10_NET, transportSettingsUnmanagedPtr); // Free memory allocated on the heap. Marshal.FreeHGlobal(transportSettingsUnmanagedPtr); Marshal.FreeHGlobal(sessionSettingsUnmanagedPtr); Marshal.FreeHGlobal(transportSettingsUnmanaged.address); Marshal.FreeHGlobal(sessionSettingsUnmanaged.seedKeyFile); } } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltSessionTerminate(); /// /// Terminates the firmware update session. This function is typically called /// once at the end of the firmware update. /// /// /// /// OpenBLT.Lib.Session.Terminate(); /// /// public static void Terminate() { BltSessionTerminate(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltSessionStart(); /// /// Terminates the firmware update session. This function is typically called /// once at the end of the firmware update. /// /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// if (OpenBLT.Lib.Session.Start() != OpenBLT.Lib.RESULT_OK) /// { /// Console.WriteLine("Could not connect to the target."); /// } /// /// public static UInt32 Start() { return BltSessionStart(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltSessionStop(); /// /// Terminates the firmware update session. This function is typically called /// once at the end of the firmware update. /// /// /// /// OpenBLT.Lib.Session.Stop(); /// /// public static void Stop() { BltSessionStop(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltSessionClearMemory(UInt32 address, UInt32 len); /// /// Requests the target to erase the specified range of memory on the target. /// /// /// Note that the target automatically aligns this to the erasable memory /// block sizes. This typically results in more memory being erased than the /// range that was specified here. Refer to the target implementation for /// details. /// /// The starting memory address for the erase operation. /// The total number of bytes to erase from memory. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// if (OpenBLT.Lib.Session.ClearMemory(0x08004000, 8196) != OpenBLT.Lib.RESULT_OK) /// { /// Console.WriteLine("Could not erase memory."); /// } /// /// public static UInt32 ClearMemory(UInt32 address, Int32 len) { // Note that parameter length was made 32-bit signed, because you typically erase the // length of a segment. When obtaining the segment info with GetSegment(), you would // then pass the length of the segment's data-array into this function, which is 32-bit // signed. return BltSessionClearMemory(address, (UInt32)len); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltSessionWriteData(UInt32 address, UInt32 len, IntPtr data); /// /// Requests the target to program the specified data to memory. /// /// /// Note that it is the responsibility of the application to make sure the /// memory range was erased beforehand. The length of the data array /// determines how many bytes are programmed. /// /// The starting memory address for the write operation. /// Byte array with data to write. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// byte[] firmwareDataAt08006000 = new byte[] /// { /// 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /// 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /// 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /// 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F /// }; /// byte[] flashData = new byte[8]; /// /// Array.Copy(firmwareDataAt08006000, 24, flashData, 0, 8); /// /// if (OpenBLT.Lib.Session.WriteData(0x08006000 + 24, flashData) != OpenBLT.Lib.RESULT_OK) /// { /// Console.WriteLine("Could not program 8 bytes at 0x08006018 in memory."); /// } /// /// public static UInt32 WriteData(UInt32 address, byte[] data) { UInt32 result = RESULT_ERROR_GENERIC; // Determine data size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; // Allocate memory on the heap for storing the data in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); // Only continue if the allocation was successful. if (dataPtr != IntPtr.Zero) { // Copy the data to unmanaged memory. Marshal.Copy(data, 0, dataPtr, data.Length); // Write the data to memory on the target. result = BltSessionWriteData(address, (UInt32)data.Length, dataPtr); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); } // Give the result back to the caller. return result; } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltSessionReadData(UInt32 address, UInt32 len, IntPtr data); /// /// Requests the target to upload the specified range from memory and store its /// contents in the specified data buffer. /// /// /// Note that the length of the data array determines how many bytes are read. /// /// The starting memory address for the read operation. /// Byte array where the uploaded data should be stored. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// /// /// public static UInt32 ReadData(UInt32 address, byte[] data) { UInt32 result = RESULT_ERROR_GENERIC; // Determine data size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; // Allocate memory on the heap for storing the data in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); // Only continue if the allocation was successful. if (dataPtr != IntPtr.Zero) { // Read the data to memory on the target. result = BltSessionReadData(address, (UInt32)data.Length, dataPtr); // Copy read data in unmanaged memory back to the data array. Marshal.Copy(dataPtr, data, 0, dataSize); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); } // Give the result back to the caller. return result; } } /// /// Wrapper for the firmware module of LibOpenBLT. /// public static class Firmware { /// /// The S-record parser enables writing and reading firmware data to and from /// file formatted as Motorola S-record. This is a widely known file format /// and pretty much all microcontroller compiler toolchains include /// functionality to output or convert the firmware's data as an S-record. /// public const UInt32 FIRMWARE_PARSER_SRECORD = 0; [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltFirmwareInit(UInt32 parserType); /// /// Initializes the firmware data module for a specified firmware file parser. /// /// /// The firmware file parser to use in this module. It should be a /// PARSER_xxx value. /// /// /// /// OpenBLT.Lib.Firmware.Init(OpenBLT.Lib.Firmware.FIRMWARE_PARSER_SRECORD); /// /// public static void Init(UInt32 parserType) { BltFirmwareInit(parserType); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltFirmwareTerminate(); /// /// Terminates the firmware data module. Typically called at the end of the /// program when the firmware data module is no longer needed. /// /// /// /// OpenBLT.Lib.Firmware.Terminate(); /// /// public static void Terminate() { BltFirmwareTerminate(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltFirmwareLoadFromFile(String firmwareFile, UInt32 addressOffset); /// /// Loads firmware data from the specified file using the firmware file parser /// that was specified during the initialization of this module. /// /// Filename of the firmware file to load. /// /// Optional memory address offset to add when loading the firmware data from /// the file.This is typically only useful when loading firmware data from a /// binary formatted firmware file. /// /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// if (OpenBLT.Lib.Firmware.LoadFromFile("demoprog.srec", 0) != OpenBLT.Lib.RESULT_OK) /// { /// Console.WriteLine("Could not load the firmware file."); /// } /// /// public static UInt32 LoadFromFile(String firmwareFile, UInt32 addressOffset) { return BltFirmwareLoadFromFile(firmwareFile, addressOffset); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltFirmwareSaveToFile(String firmwareFile); /// /// Writes firmware data to the specified file using the firmware file parser /// that was specified during the initialization of this module. /// /// Filename of the firmware file to write to. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// if (OpenBLT.Lib.Firmware.SaveToFile("myfirmware.srec") != OpenBLT.Lib.RESULT_OK) /// { /// Console.WriteLine("Could not save the firmware file."); /// } /// /// public static UInt32 SaveToFile(String firmwareFile) { return BltFirmwareSaveToFile(firmwareFile); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltFirmwareGetSegmentCount(); /// /// Obtains the number of firmware data segments that are currently present /// in the firmware data module. /// /// The total number of segments. /// /// /// UInt32 segmentCount = OpenBLT.Lib.Firmware.GetSegmentCount(); /// Console.WriteLine("Number of segments: {0}", segmentCount); /// /// public static UInt32 GetSegmentCount() { return BltFirmwareGetSegmentCount(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr BltFirmwareGetSegment(UInt32 idx, out UInt32 address, out UInt32 len); /// /// Obtains the contents of the firmware data segment that was specified by /// the index parameter. /// /// /// The segment index. It should be a value greater or equal to zero and /// smaller than the value returned by GetSegmentCount(). /// /// Tuple with segment data and base address. /// /// /// var segment = OpenBLT.Lib.Firmware.GetSegment(0); /// Console.WriteLine("Base address: {0:X}h", segment.address); /// Console.WriteLine("Length: {0}", segment.data.Length); /// Console.WriteLine("First data: {0:X2}h {1:X2}h {2:X2}h", segment.data[0], segment.data[1], segment.data[2]); /// /// public static (byte[] data, UInt32 address) GetSegment(UInt32 idx) { byte[] data = new byte[0]; UInt32 address = 0; UInt32 len; IntPtr dataPtr; // Obtain the segment info. dataPtr = BltFirmwareGetSegment(idx, out address, out len); // Note that the DLL function returns a 32-bit unsigned. It is subsequently // used in functions where it is assumed to be 32-bit signed. A segments will // never be larger than the 32-bit signed maximum value, so that will work // fine. Still good to double-check though. Debug.Assert(len <= Int32.MaxValue); // Only continue if the returned data pointer is not a NULL pointer and when // the segment has a non-zero length. if ((dataPtr != IntPtr.Zero) && (len > 0) && (len <= Int32.MaxValue)) { // Resize the array such that it can store all bytes from the segment. Array.Resize(ref data, (Int32)len); // Copy the segment data to the resulting data array. Marshal.Copy(dataPtr, data, 0, (Int32)len); } // Give the result back to the caller. return (data, address); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltFirmwareAddData(UInt32 address, UInt32 len, IntPtr data); /// /// Adds data to the segments that are currently present in the firmware data /// module.If the data overlaps with already existing data, the existing data /// gets overwritten.The size of a segment is automatically adjusted or a new /// segment gets created, if necessary. /// /// Base address of the firmware data. /// Array with data bytes that should be added. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// byte[] newData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; /// OpenBLT.Lib.Firmware.AddData(0x08100000, newData); /// /// public static UInt32 AddData(UInt32 address, byte[] data) { UInt32 result = RESULT_ERROR_GENERIC; // Determine data size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; // Allocate memory on the heap for storing the data in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); // Only continue if the allocation was successful. if (dataPtr != IntPtr.Zero) { // Copy the data to unmanaged memory. Marshal.Copy(data, 0, dataPtr, data.Length); // Add the data to the already loaded firmware data. result = BltFirmwareAddData(address, (UInt32)data.Length, dataPtr); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); } // Give the result back to the caller. return result; } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltFirmwareRemoveData(UInt32 address, UInt32 len); /// /// Removes data from the segments that are currently present in the firmware /// data module.The size of a segment is automatically adjusted or removed, if /// necessary. /// /// Base address of the firmware data. /// Number of bytes to remove. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// OpenBLT.Lib.Firmware.RemoveData(0x08100000, 8); /// /// public static UInt32 RemoveData(UInt32 address, UInt32 len) { return BltFirmwareRemoveData(address, len); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltFirmwareClearData(); /// /// Clears all data and segments that are currently present in the firmware /// data module. /// /// /// /// OpenBLT.Lib.Firmware.ClearData(); /// /// public static void ClearData() { BltFirmwareClearData(); } } /// /// Wrapper for the utility module of LibOpenBLT. /// public static class Util { /// /// Wrapper for the CRC utilities of LibOpenBLT. /// public static class Crc { [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt16 BltUtilCrc16Calculate(IntPtr data, UInt32 len); /// /// Calculates a 16-bit CRC value over the specified data. /// /// Array with bytes over which the CRC16 should be calculated. /// The 16-bit CRC value. /// /// /// byte[] crcData = new byte[] { 0x55, 0xAA, 0x00, 0xFF }; /// UInt16 crc16 = OpenBLT.Lib.Util.Crc.Calculate16(crcData); /// /// public static UInt16 Calculate16(byte[] data) { UInt16 result = 0; // Determine data size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; // Allocate memory on the heap for storing the data in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); // Only continue if the allocation was successful. if (dataPtr != IntPtr.Zero) { // Copy the data to unmanaged memory. Marshal.Copy(data, 0, dataPtr, data.Length); // Calculate the CRC16 over the data. result = BltUtilCrc16Calculate(dataPtr, (UInt32)data.Length); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); } // Give the result back to the caller. return result; } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltUtilCrc32Calculate(IntPtr data, UInt32 len); /// /// Calculates a 32-bit CRC value over the specified data. /// /// Array with bytes over which the CRC32 should be calculated. /// The 32-bit CRC value. /// /// /// byte[] crcData = new byte[] { 0x55, 0xAA, 0x00, 0xFF }; /// UInt32 crc32 = OpenBLT.Lib.Util.Crc.Calculate32(crcData); /// /// public static UInt32 Calculate32(byte[] data) { UInt32 result = 0; // Determine data size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; // Allocate memory on the heap for storing the data in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); // Only continue if the allocation was successful. if (dataPtr != IntPtr.Zero) { // Copy the data to unmanaged memory. Marshal.Copy(data, 0, dataPtr, data.Length); // Calculate the CRC32 over the data. result = BltUtilCrc32Calculate(dataPtr, (UInt32)data.Length); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); } // Give the result back to the caller. return result; } } /// /// Wrapper for the time utilities of LibOpenBLT. /// public static class Time { [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern Int32 BltUtilTimeGetSystemTime(); /// /// Get the system time in milliseconds. /// /// /// Time in milliseconds. /// /// /// /// Console.WriteLine("Current system time: {0}", OpenBLT.Lib.Util.Time.GetSystemTime()); /// /// public static Int32 GetSystemTime() { return BltUtilTimeGetSystemTime(); } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern void BltUtilTimeDelayMs(UInt16 delay); /// /// Performs a delay of the specified amount of milliseconds. /// /// Delay time in milliseconds. /// /// /// OpenBLT.Lib.Util.Time.DelayMs(1000); /// /// public static void DelayMs(UInt16 delay) { BltUtilTimeDelayMs(delay); } } /// /// Wrapper for the cryptography utilities of LibOpenBLT. /// public static class Crypto { /// /// Wrapper for the AES256 cryptography utilities of LibOpenBLT. /// public static class Aes256 { [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltUtilCryptoAes256Encrypt(IntPtr data, UInt32 len, IntPtr key); /// /// Encrypts the bytes in the specified data-array, using the specified /// 256-bit (32 bytes) key.The results are written back into the same array. /// /// /// The number of bytes in the data-array must be a multiple of 16, as this /// is the AES256 minimal block size. /// /// /// Byte array with data to encrypt. The encrypted bytes are stored in the /// same array. /// /// The 256-bit encryption key as a array of 32 bytes. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// byte[] cryptoKey = new byte[] /// { /// 0x83, 0x23, 0x44, 0x28, 0x47, 0x2B, 0x4B, 0x62, /// 0x50, 0x65, 0x53, 0x68, 0x56, 0x6D, 0x59, 0x71, /// 0x33, 0x74, 0x36, 0x77, 0x39, 0x7A, 0x24, 0x43, /// 0x26, 0x46, 0x29, 0x48, 0x40, 0x4D, 0x69, 0x39 /// }; /// /// byte[] originalData = new byte[] /// { /// 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /// 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /// 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /// 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F /// }; /// /// OpenBLT.Lib.Util.Crypto.Aes256.Encrypt(originalData, cryptoKey); /// /// public static UInt32 Encrypt(byte[] data, byte[] key) { UInt32 result = RESULT_ERROR_GENERIC; // Determine data and key size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; Int32 keySize = Marshal.SizeOf(key[0]) * key.Length; // Only continue if the key has at least 32 bytes (256-bit key). if (keySize >= 32) { // Allocate memory on the heap for storing the data and key in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); IntPtr keyPtr = Marshal.AllocHGlobal(keySize); // Only continue if the allocation was successful. if ((dataPtr != IntPtr.Zero) && (keyPtr != IntPtr.Zero)) { // Copy the data and key to unmanaged memory. Marshal.Copy(data, 0, dataPtr, data.Length); Marshal.Copy(key, 0, keyPtr, key.Length); // Encrypt the data using the key. Note that the encrypted data overwrites // the data in unmanaged memory. result = BltUtilCryptoAes256Encrypt(dataPtr, (UInt32)dataSize, keyPtr); // Copy encrypted data in unmanaged memory back to the data array. Marshal.Copy(dataPtr, data, 0, dataSize); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); Marshal.FreeHGlobal(keyPtr); } } // Give the result back to the caller. return result; } [DllImport(LIBNAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 BltUtilCryptoAes256Decrypt(IntPtr data, UInt32 len, IntPtr key); /// /// Decrypts the bytes in the specified data-array, using the specified /// 256-bit (32 bytes) key.The results are written back into the same array. /// /// /// The number of bytes in the data-array must be a multiple of 16, as this /// is the AES256 minimal block size. /// /// /// Byte array with data to decrypt. The decrypted bytes are stored in the /// same array. /// /// The 256-bit decryption key as a array of 32 bytes. /// RESULT_OK if successful, RESULT_ERROR_xxx otherwise. /// /// /// byte[] cryptoKey = new byte[] /// { /// 0x83, 0x23, 0x44, 0x28, 0x47, 0x2B, 0x4B, 0x62, /// 0x50, 0x65, 0x53, 0x68, 0x56, 0x6D, 0x59, 0x71, /// 0x33, 0x74, 0x36, 0x77, 0x39, 0x7A, 0x24, 0x43, /// 0x26, 0x46, 0x29, 0x48, 0x40, 0x4D, 0x69, 0x39 /// }; /// /// byte[] encryptedData = new byte[] /// { /// 0x43, 0x34, 0xd1, 0x54, 0xa2, 0xf0, 0x48, 0x76, /// 0x0e, 0x30, 0xf8, 0xa0, 0x92, 0x4f, 0xbc, 0xce, /// 0x06, 0x9c, 0x29, 0xf7, 0x24, 0x58, 0x79, 0x4e, /// 0x94, 0xeb, 0xd0, 0x35, 0xfd, 0xae, 0xf9, 0x88 /// }; /// /// OpenBLT.Lib.Util.Crypto.Aes256.Decrypt(encryptedData, cryptoKey); /// /// public static UInt32 Decrypt(byte[] data, byte[] key) { UInt32 result = RESULT_ERROR_GENERIC; // Determine data and key size. Int32 dataSize = Marshal.SizeOf(data[0]) * data.Length; Int32 keySize = Marshal.SizeOf(key[0]) * key.Length; // Only continue if the key has at least 32 bytes (256-bit key). if (keySize >= 32) { // Allocate memory on the heap for storing the data and key in unmanaged memory. IntPtr dataPtr = Marshal.AllocHGlobal(dataSize); IntPtr keyPtr = Marshal.AllocHGlobal(keySize); // Only continue if the allocation was successful. if ((dataPtr != IntPtr.Zero) && (keyPtr != IntPtr.Zero)) { // Copy the data and key to unmanaged memory. Marshal.Copy(data, 0, dataPtr, data.Length); Marshal.Copy(key, 0, keyPtr, key.Length); // Decrypt the data using the key. Note that the decrypted data overwrites // the data in unmanaged memory. result = BltUtilCryptoAes256Decrypt(dataPtr, (UInt32)dataSize, keyPtr); // Copy Decrypted data in unmanaged memory back to the data array. Marshal.Copy(dataPtr, data, 0, dataSize); // Free the unmanaged memory. Marshal.FreeHGlobal(dataPtr); Marshal.FreeHGlobal(keyPtr); } } // Give the result back to the caller. return result; } } } } } }