From 8e486e596be084634c2f3ecd88cf185a1969209d Mon Sep 17 00:00:00 2001 From: Frank Voorburg Date: Fri, 19 Mar 2021 11:27:39 +0000 Subject: [PATCH] Refs #780. Integrate LibOpenBLT C# bindings into the trunk. git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@834 5dc33758-31d5-4daf-9ae8-b24bf3d40d73 --- .../LibOpenBLT/bindings/csharp/README.md | 115 ++ .../LibOpenBLT/bindings/csharp/openblt.cs | 1410 +++++++++++++++++ 2 files changed, 1525 insertions(+) create mode 100644 Host/Source/LibOpenBLT/bindings/csharp/README.md create mode 100644 Host/Source/LibOpenBLT/bindings/csharp/openblt.cs diff --git a/Host/Source/LibOpenBLT/bindings/csharp/README.md b/Host/Source/LibOpenBLT/bindings/csharp/README.md new file mode 100644 index 00000000..4b7908b4 --- /dev/null +++ b/Host/Source/LibOpenBLT/bindings/csharp/README.md @@ -0,0 +1,115 @@ +## C# wrapper for LibOpenBLT +The OpenBLT Host Library ([LibOpenBLT](https://www.feaser.com/openblt/doku.php?id=manual:libopenblt)) contains an application programming interface (API) for communicating with a microcontroller target, running the OpenBLT bootloader, for making firmware updates on the target. The goal of the OpenBLT Host Library is to empower you to quickly and efficiently create your own firmware update tool, in case you don’t prefer the standard MicroBoot and BootCommander tools that are included in the OpenBLT bootloader package. + +This directory contains the C# wrapper for LibOpenBLT, which enables you to quickly develop your own firmware update tool in the C# programming language, for example with Visual Studio. + +### Using the wrapper +To use the C# wrapper for LibOpenBLT, add the file **openblt.cs** from this directory to your C# project. + +Here is a minimal C# console program that demonstrates how to display the version of LibOpenBLT: + +```c# +using System; + +namespace ConsoleApp +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("LibOpenBLT version number: {0}", OpenBLT.Lib.Version.GetNumber()); + } + } +} +``` + +### Run-time libraries +Copy the LibOpenBLT related run-time libraries into the directory where your program's executable is located. Refer to the following section on the OpenBLT Wiki for a overview of these run-time libraries: + +https://www.feaser.com/openblt/doku.php?id=manual:libopenblt#run-time_libraries + +These run-time libraries can be found in the ./Host directory of the OpenBLT bootloader package. These run-time libraries should also be included, when distributing your program. + +### Configure platform target + +Under Microsoft Windows, the LibOpenBLT shared library (**libopenblt.dll**) is 32-bit. For this reason you need to build your own C# program as a 32-bit application as well. + +To configure this, go to your project's properties in Microsoft Visual Studio. In the *Build* settings, set the **Platform target** to **x86**. + +### Example program + +The following console program demonstrates how to use the C# wrapper for LibOpenBLT to perform a firmware update via RS232. It can be used as a starting point and reference for developing your own firmware update tool. + +```c# +using System; + +namespace ConsoleApp +{ + class Program + { + static void Main(string[] args) + { + // ------------ Display library info ---------------------------------------- + Console.WriteLine("LibOpenBLT version string: {0}", OpenBLT.Lib.Version.GetString()); + + // ------------ Initialization ---------------------------------------------- + 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 transportSettingsRs232; + transportSettingsRs232.portName = "COM14"; + transportSettingsRs232.baudrate = 57600; + + OpenBLT.Lib.Session.Init(sessionSettings, transportSettingsRs232); + OpenBLT.Lib.Firmware.Init(OpenBLT.Lib.Firmware.FIRMWARE_PARSER_SRECORD); + + // ------------ Load firmware ----------------------------------------------- + if (OpenBLT.Lib.Firmware.LoadFromFile("demoprog_stm32f091.srec", 0) != OpenBLT.Lib.RESULT_OK) + { + Console.WriteLine("Could not load firmware data from the S-record."); + } + + // ------------ Connect to target ------------------------------------------- + if (OpenBLT.Lib.Session.Start() != OpenBLT.Lib.RESULT_OK) + { + Console.WriteLine("Could not connect to the target."); + } + + // ------------ Erase flash ------------------------------------------------- + for (UInt32 segmentIdx=0; segmentIdx + /// 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; + } + } + } + } + } +}