G120 RLP Procedure Args

I’m working with some RLP code and I’m having problems with something that should be simple.

Below is my RLP code:

#include "RLP.h"
 #include "LPC17xx.h"


int RlpTest(void **args) {
    return 12;
}

int UpdateLinearInterpolation(void** args) {
    int length = *(int*) (args[0]); //length of the array
    int position = *(int*) (args[1]); //position of the interpolation between 0-256;


    return length;
}

This is my managed code:

/// <summary>
        /// Initializes the RLP procedures.
        /// </summary>
        static void InitializeRLP()
        {
            Debug.Print("->Initialize RLP\r\n");

            var elfData = Resources.GetBytes(Resources.BinaryResources.BalanceBoard);
            RLP.LoadELF(elfData);
            RLP.InitializeBSSRegion(elfData);
            RLP.Procedure test = RLP.GetProcedure(elfData, "RlpTest");
            rlpUpdateLinearInterpolation = RLP.GetProcedure(elfData, "UpdateLinearInterpolation"); 

            elfData = null; //we don't need this anymore.

            int result = test.Invoke(); //run the test
            int length = rlpUpdateLinearInterpolation.Invoke(16, 0); //, array,array,array});
            Debug.Print("Test = " + result);
            Debug.Print("Length = " + length); 
        }

When I run this, my output is as follows:

[quote]->Initialize RLP

Test = 12
Length = 536875525[/quote]

I don’t understand why my length variable isn’t correct. The “RlpTest” function is working correctly, and the second function will output the correct value, if I return a constant. So I must be doing something wrong with passing int the argument. Any suggestions about what I’m doing wrong? I would expect Length to equal 16. Thanks!

Try casting the 16 to an int before passing to rlp.

Any constant in C# is an int by Default, so I guess that’s not the Problem.
At a 1st glance I can not see anything thats different to the samples in the dcos with one exception.
All samples uses variables as Parameters to invoke.
I’m not sure, but this might make a difference.
If that does not help, I guess that something with your C Compiler/linker configuration might be wrong (like stack oder).

Is there a difference between
void** args
and
void **args

?

no. the whitespaces between operators and/or identifiers have no influence in C

1 Like

I tried this first and, as Reinhard predicted, it didn’t make a difference.

I also tried passing my length as a variable parameter, instead of a constant and I got the same incorrect result. The value it returned was different (-1607463356 instead of 536875525), but still not right.

I’m using EmBlocks to create my .elf file. I followed the procedure in the “RLP in Depth” document that I believe I was directed to from the GHI site. Any suggestions on what to look for regarding the Compiler/Linker configuration?

@ jfox3721 - I presume you used Simons templates from RLPid? Do they example templates work ok?

This works fine for me doing much more complex stuff, so I am at a bit of a loss.

Clutching at straws here but is Length a keyword?

I thought this also at first, but that wouldn’t make sense with the syntax, right? Any variable that is created and managed within the RLP is returned correctly. My issue has to be the passing of a variable from managed to unmanaged.

Yeah, I’m using Simon’ s extensions. I just noticed one thing…the template is titled (G120 4.3). My G120 module is flashed with 4.2. Think this would cause a problem? I use VS2010 at work so I was hoping to stick with 4.2 as long as I could.

There have been some changes with RLP so that could easily be it. I can’t find a link to old RLP example files.

Definitely. RLP function signatures for 4.2 and 4.3 are totally incompatible.

Initial versions of “RLP in Depth” had also old signatures described. I’ll try to look for them once I get home tommorow.

Not sure if it works, but try a quick and dirty workaround until we find things out:


int UpdateLinearInterpolation(void** args) {
    int length = *(int*) (args[1]); //length of the array
    int position = *(int*) (args[2]); //position of the interpolation between 0-256;


    return length;
}
1 Like

Hi Simon. Unfortunately that didn’t fix things. I’ll look around for the older signatures in the mean time. Sounds like that is most likely my problem.

1 Like

@ jfox3721 - I don’t have the old documentation, but I pulled up some old code that I had done with RLP on the FEZ Spider in the 4.1 time frame, the signatures at the time looked like the following.


int yourFunction(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)

That first generalArray can be a pointer to a few different data types for example, float, int, short etc.

Hope this helps.

Function signature indeed didn’t change moving from 4.1 to 4.2. But I recommend moving to 4.3. GHI firmware 4.2 is no longer supported for reason; it was a disaster, at least for G400. 4.3 works much, much better now.

A little excerpt from early manual versions. Hope it helps.

*generalArray
As the name implies, this is just a simple array that is passed from managed code. One important note: if you change the content in native code, changes will be seen in managed code, too. This is the main mechanism of exchanging data between managed and native code.
It can only be used by using InvokeEx() method. It accepts byte[], Int32[], float[] and other array types, but bear in mind that there’s a performance penalty of invoking, and byte[] arrays are the ones least penalized.

**args
Wherever you use Invoke() or InvokeEx() method, you can pass up to 8 arguments (well, excluding the *generalArray in InvokeEx()) of any kind. **args contains all of them. A spooky double pointer, isn’t it? I never really liked pointers, and I surely don’t like double pointers, and I definitely hate void pointers, but it is that “up to 8 arguments of any kind” that forces using one.
Treat it just like an array. There will be example below of how to parse it in native code.

argsCount
Ahhh, this is one is easy and straightforward: it shows how many arguments there were passed from managed code. Again, excluding the *generalArray.

*argSize
This is just an Int32 array, telling us how big each of the passed argument is. It is not very useful when passing ordinary, fixed-size arguments, like integers or floats; this knowledge is available at compile time. Int32 is always 4 bytes long, as is the float. Double takes 8 bytes. Always. Not much space for imagination here. However, things change if passing arrays. In NETMF, arrays are often created dynamically, at runtime, thus their length is not known at compile time. Sometimes this is an incredibly useful feature (for example, when working with communications), but this can be a problem in native code. This is where *argSize helps: one can check how long the provided arrays is.

+100 for that.

Pointers are a fun Thing to Play with. Once you understand how all the Operator work with pointers, you can do a lot of fun (and bad) stuff.
The actual type of the pointer does not really matter at all.

But I have to admit that having no pionters (like in C#, by Default) makes programming a lot more fail safe. This is one of the reasons I use it for nearly 10 years now.

@ Reinhard Ostermeier - so the type of the pointer is just a hint to the type of the data it’s pointing at? Using a void is just a clue that the type can change at runtime?

That’s not the full story.
The type also has influence on incrementing the pointer.
if you add 1 to a void or byte pointer, the address gets incremented by 1.
if you add 1 to a short*, the address gets incremented by 2, for int* its 4 (on 32 bit machines) and so on.

1 Like