[Feature] Provide wrapper functions for the C# (.NET) world.
For my purposes, I need a possibility to call the BLF parser/writer within the C# code. I’m not that much experienced in C++ or Glue Code development, however I’ve fiddled a little bit around and created the neccessary bindings. Please take a look at the zipped sources files for the wrapper functions.
In order to be able to call the C++ functions from the dll the following C# code will be needed for e.g. the parser:
void Main()
{
string fileName = @"can_fd_write_test.blf";
var parserPtr = CreateParser();
var nrOfParsedMessages = Parse(parserPtr, fileName);
nrOfParsedMessages.Dump();
for (int i = 0; i < nrOfParsedMessages; i++)
{
var canMsg = GetMessageAt(parserPtr, i);
var dataLen = GetDataLenFromDlc(canMsg.dlc);
IntPtr canMsgPayload = GetPayload(parserPtr, i);
byte[] fixedData = new byte[dataLen];
Marshal.Copy(canMsgPayload, fixedData, 0, fixedData.Length);
var blfMsg = new BlfMessage(){BlfCanMessage = canMsg, Payload = fixedData};
blfMsg.Dump();
}
}
public struct BlfMessage
{
public BlfCanMessage BlfCanMessage;
public byte[] Payload;
}
private static int GetDataLenFromDlc(uint dlc)
{
return dlc switch
{
9 => 12,
10 => 16,
11 => 20,
12 => 24,
13 => 32,
14 => 48,
15 => 64,
_ => (int)dlc
};
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BlfCanMessage
{
public uint dlc;
public uint canId;
public ushort channel;
public byte flags; // bit 0: TX
public IntPtr payload;
}
[DllImport("BlfParser.dll", EntryPoint = "Parse", CharSet = CharSet.Ansi)]
static extern int Parse(IntPtr ptr, string filePath);
[DllImport("BlfParser.dll", EntryPoint = "GetMessage", CharSet = CharSet.Ansi)]
static extern BlfCanMessage GetMessageAt(IntPtr ptr, int pos);
[DllImport("BlfParser.dll", EntryPoint = "CreateParser", CharSet = CharSet.Ansi)]
static extern IntPtr CreateParser();
[DllImport("BlfParser.dll", EntryPoint = "GetPayload", CharSet = CharSet.Ansi)]
static extern IntPtr GetPayload(IntPtr ptr, int pos);
and for the writer:
using System.Runtime.InteropServices;
void Main()
{
string fileName = @"test.blf";
IntPtr blfWriterPtr = CreateWriter();
OpenFile(blfWriterPtr, fileName);
byte[] rawData1 = {0, 0, 0, 0, 70, 68, 0, 1, 1, 2, 3, 4};
byte[] rawData2 = {0, 0, 0, 0, 70, 11, 0, 32, 1, 2, 3, 4};
List<byte[]> rawDataList = new List<byte[]>();
rawDataList.Add(rawData1);
rawDataList.Add(rawData2);
foreach(var rawData in rawDataList)
{
int size = Marshal.SizeOf(rawData[0]) * rawData.Length;
IntPtr pnt = Marshal.AllocHGlobal(size);
// Copy the array to unmanaged memory.
Marshal.Copy(rawData, 0, pnt, rawData.Length);
var blfCanMsg = new BlfWriteCanMessageStruct()
{
channel = 1,
canId = 1175,
dlc = 9,
flags = 0
};
WriteCanFdMsg(blfWriterPtr, blfCanMsg, pnt);
Marshal.FreeHGlobal(pnt);
}
CloseFile(blfWriterPtr);
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BlfWriteCanMessageStruct
{
public uint dlc;
public uint canId;
public ushort channel;
public byte flags; // bit 0: TX
}
[DllImport("BlfParser.dll", EntryPoint = "CloseFile", CharSet = CharSet.Ansi)]
static extern void CloseFile(IntPtr writerIntPtr);
[DllImport("BlfParser.dll", EntryPoint = "WriteCanMsg", CharSet = CharSet.Ansi)]
static extern void WriteCanMsg(IntPtr writerIntPtr, BlfWriteCanMessageStruct blfCanMessage, IntPtr payload);
[DllImport("BlfParser.dll", EntryPoint = "CreateWriter", CharSet = CharSet.Ansi)]
static extern IntPtr CreateWriter();
[DllImport("BlfParser.dll", EntryPoint = "OpenFile", CharSet = CharSet.Ansi)]
static extern bool OpenFile(IntPtr blfWriterPtr, string filename);
[DllImport("BlfParser.dll", EntryPoint = "WriteCanFdMsg", CharSet = CharSet.Ansi)]
static extern void WriteCanFdMsg(IntPtr writerIntPtr, BlfWriteCanMessageStruct blfCanMessage, IntPtr payload);
Both C# snippets can be run within the LinqPad tool by providing the location of the dlls as an additional reference:
The attachment also contains the built dlls.
@Tobias Lorenz Are you interested in such bindings? The bindings that I’ve created are just a working sw-prototype, so there is definitely some refactoring needed
Comments (5)
-
repo owner -
repo owner - changed status to open
-
repo owner -
assigned issue to
-
assigned issue to
-
reporter Yes, I fully agree. You can put it into the src/Vector/BLF/docs/examples directory.
By the way, is it possible to use this library for commercial projects?
-
repo owner Yes, that’s exactly my business model. For use in commercial projects I can provide you with a commercial license. I propose you send me an e-mail with the name of your company and product in which you want to use the license, and I can send you a license contract proposal and offer.
- Log in to comment
I have no C# experience, and also never developed glue code.
But I appreciate the provided example code and if you agree, I would like to have this within src/Vector/BLF/docs/examples. I’ll check through it and probably add some documentation, where useful. Also there should be a note somewhere, that this is provided under public domain, so to say “license free”.