Calling native code on the Endpoint

One of the things I’ve always wanted to do on the SITCore devices was to call native code. So, what’s the first thing I did when I got my Endpoint? Called a native code library, of course!

Check out the src/pinvoke example (that’s the only one, but there’s more to come) : Pervasive Digital Endpoint Examples

This example shows how to create, build, and package a simple native library and then call that from dotnet on either windows or the Endpoint devices. Read the src/pinvoke/readme.md carefully - there’s some fiddly setup involved, as you need to install a toolchain for building arm32 Linux binaries to create the native library for the Endpoint.

Why call native code? Well, for some devices the manufacturer provides proprietary binary files (I’m looking at you Bosch). In other cases, you may want access to resources or capabilities that aren’t easily accessible or fully performant from dotnet. Dotnet is an incredible engineering accelerator, but there are still times when you need to dive in closer to the metal.

Hope you find this interesting and/or useful.

using System.Runtime.InteropServices;

#if WINDOWS_EMULATION
[DllImport("mathlib.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern Int32 add(Int32 a, Int32 b);
#else
[DllImport("mathlib.so", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern Int32 add(Int32 a, Int32 b);
#endif

Int32 val1 = 12;
Int32 val2 = 30;

var sum = add(val1, val2);
Console.WriteLine($"The answer to life, the universe and everything is {sum}");
6 Likes

Endless possibilities. Very impressive.

1 Like

Do you think it might be possible add a C project to a Visual Studio solution (that already has a C# Endpoint project) so that Visual Studio can be used to build the C object/dll ?

Of course we’d need to be able to specify a CPU target of Arm, not sure if the standard Microsoft C compiler offers that. Also how do you package the generated native obj/dll so that it can be published to the board when we debug our C# project?

I also use VisualGDB for developing in C on STM32 MCUs in Visual Studio, I suspect I’d have no trouble using that but have no idea yet, how to use that to create a binary loadable by .Net

If you add it as a CMake project, yes. VS 2022 knows how to build CMake projects. Install the arm toolchain as described in the example, and then add that CMake folder to your solution. At least that’s where I would start. I haven’t tried that myself because I find VSCode perfectly adequate and do prefer working on Mac or Linux devices.

Trying to get it working as an MSBuild project is probably a pretty big mountain to climb, so I would start with trying to add the ARM native project to your solution in its current CMake format.

Alright, many thanks for this. I did a huge amount of interop about ten years ago, where we developed a large C Win32 API that we called from .Net Framework, I recall doing the converse too, passing a delegate into C code so that C code could call into managed code, can’t recall the details but I could dig out that code, have you tried this yourself with Endpoint?

I did a bit of digging and see that VS supports an ARM set of build tools, I wasn’t aware of that.

image

Then in VS I select a build target of ARM:

I then built a tiny bit of code and specified to generate an assembly listing which I can see is certainly ARM CPU code.

I’ll try to get this working, see if I can do what you did wholly from within VS 2022 (because I’m lazy and will do anything to avoid learning all that CMake stuff !!)

1 Like

This “almost” works. It seems that even though I have the ARM compiler tools installed for Visual Studio, there’s a stumbling block.

It seem that the build in VS forces a COFF outpute file (.DLL) whereas (from what I can gather) the runtime on the board expects a .SO file (which is ELF a different format to COFF). I get the message:

/root/.epdata/EndpointTesting/NativeLibrary.so: invalid ELF header

The build creates a .DLL and I (in an act of desperation) rename that to .SO but of course it fails to load. This seems to be something caused by the fact it’s .Net hosted on Linux, if there was a way to have the Endpoint host somehow accept either .ELF or .DLL library formats then I think we could create VS Solutions that contained both C# and C projects and be able to write interop code with no special tooling, just standard “out of the box” Visual Studio.

I can find no way to instruct the C compiler to create .ELF files, despite that fact that it is an ARM compiler…

Trying to force the MSVC compiler to do this is a big mountain to climb, but if mountain climbing is your hobby, have at it. You’ll need to set enough options to get it to compile an image compatible with arm-none-linux-gnueabihf. That is, arm32, no variant, linux target OS environment, GNU binary interface, and hard-float math. I doubt the MSVC compiler will get you there, especially due to the linux target requirement. I think it always assumes a Windows target environment.

I do love me a challenge too, but if running code is the goal, I’d use the toolchain specified in the link in the original post.

Yes, but if I can get it sorted it makes my life easier, just trying to avoid so much involved tooling.

There might be another way to do this, I will try later. I use VisualGDB to write code in C for STM32 devices. This is a very capable Visual Studio extension and has all the industry standard toolchains and compilers.

VisualGDB also supports Linux projects and that looks promising, I might already have the toolchain you see, as part of VisualGDB, just never bothered to look into Linux…

Almost there:

/root/.epdata/EndpointTesting/LinuxProject1.so: wrong ELF class: ELFCLASS64

Seems the build is for 64 Bit ARM and that’s not an option, seems like the toolchains themselves are what determines this…

Success !

I had to download a new toolchain so followed your directions and then I tweaked the VisualGDB project to use that and it all works!

So my native code can now be developed in Visual Studio as VisualGDB Linux Shared Library projects and consumed by the managed apps.

I’ll probably be able to add a new VisualGDB Linux project to an Endpoint Solution and then have all native code as a project in same solution.

Sorry if this sounds all over the place but I’m totally new to all these toolchanins and Linux and so on.

2 Likes

is there free version?

No, but its pretty inexpensive. I tried it a few years ago and was pleasantly surprised, I did a few of their many tutorials and stuff just works. Because its Visual Studio, the whole thing feels solid, VisualGDB has been impressively reliable, granted my needs are modest but I also have 45 years experience in software (and originally studied electronics full time before then).

The trial is worth getting, you’ll get 30 days and I’m sure as an experienced MCU guy, you’ll find it great value for money.

They support a huge number of MCUs and if you have some ST Nucleo boards around, there are many tutorials that’ll quickly reveal the quality of this product. You’ll no doubt appreciate its features far better than me since you do this stuff professionally.

1 Like

If you don’t mind, could you give us your opinion between VisualGDB and VSC?

Why don’t you use VSC? Just want to learn.

By “VSC” you mean Visual Studio Code?

Personally I strive to have simple workflows for developing stuff, the simpler the better - it’s a personal thing accrued over decades of working. VS Code is good, hugely popular but I’ve worked with Visual Studio since before Windows NT, used it write compilers back in the 90s.

So I find VS Code needs me to learn too much, install this or that extension and it doesn’t support solutions (.sln) so requires an effort that I’m too lazy to devote! I use Visual Studio for my professional .Net work, I live inside it daily.

VisualGDB does everything it claims to, it just works flawlessly, it feels like it’s an inherent part of Visual Studio, seamless. The debugging support is excellent, I can debug at the assembly level, step through ARM instructions as the code executes on the board.

It exposes a huge amount of MCU specific stuff, professionals like some of the people on this forum, would likely feel very much at home.

Before I bought VisualGDB I did this little tutorial and it just worked, no ifs, no buts, no surprises. Its clear too, this is a serious system, one can do far more than simple blinkers here.

You can even import CubeMX projects into VisualGDB, that’s a fully supported capability.

Just a small update, I leveraged the sample kindly provided by Martin Calsyn and although I did not do exactly as he did, I did grab the toolchain he used and was then able to create a VisualGDB “Linux” project. That kind of project lets you create a 32 bit Linux .SO file as the build output. (Their example builds a static library but a shared SO library is just an option click).

I then manually added that project to an existing Visual Studio solution:

image

I defined the build order so that the final .Net app project depends on the Linux project:

image

The .Net project (the Endpoint test app) drags that .SO into its build outputs as shown by Martin:

And I can now call that C code from C# much as Martin did. This means I can edit the C and C# in the same Visual Studio solution and just rebuild and test and it all works nicely.

I can’t (yet) “step-in” to the C code from C# which one should be able to do ordinarily, but that’s not a big concern for me.

There is tight integration too with CubeMX projects.

5 Likes

I would also like to recommend VisualGDB, I’m usually skeptical of paid add-ons, but I have found it really worthwhile as it makes things that were “just possible” easy.

I’m currently using it to build and debug a large codebase running on embedded RT Linux ARM systems, the source is on my PC, the compile and GDB run on a virtual Linux machine, and the executable code and GDB stub on the actual hardware, and it just works. Debugging native C/C++ is the same as debugging C# on the NetMF/TinyCLR boards.

The same systems (industrial controllers) have one of our Raspberry Pi Pico boards that does custom keyboard to USB interface and temperature reading, again build/debug using VisualGDB and having the same (VS2022) interface.

We run simulators for the control systems, built from the same source code but running directly on Windows, so we get the same VS2022 interface again, which makes it simple to switch between projects.

I’ve nothing against VS Code, I use it quite a lot on Windows and Linux, but at present when I’m doing a fair bit of maintenance on NetMF and TinyCLR projects in Visual Studio I like the convenience of keeping to the same familiar UI.

Thumbs up for VisualGDB. Well worth the price.

3 Likes