LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Persistence of objects in VIs called from C

Solved!
Go to solution

In my first case, I have a single VI compiled to a DLL. This VI does three different things, depending on the function call:

 

callout_1.png

This is the first operation. It opens a connection to a UDP stream server. "ID" and "SA" are commands to tell the server to start send UDP data. The function call is:

 

callout(int Func, char *Address, char *DataOut, int Len);

 

Func is the operation I want to do, Address is the IP address to the server, DataOut is a container for the returned data and Len is the size of the container.

 

To start receiving data, I write:

 

callout(1, addr, data, 5000);

 

DataOut is ignored in this case. To retrieve UDP packets the next operation is used:

 

callout_2.png

The call is:

 

callout(2, addr, data, 5000);

 

In this case, Address isn't used. 5000 bytes of data is copied to the location where data points.

 

callout_3.png

And finally, this operation closes the stream:

 

callout(3, addr, data, 5000);

 

"SC" is the command to close the stream.

 

The above steps work just fine. The state of the VI is persistent between the function calls, and the connection saved in Connection ID is usable all the time.

 

What I'm trying to do now is streamline the operations by dividing this VI into three separate VIs. The first operation looks like this now:

 

callout_4.png

In this case I try to save pointers to relevant objects in my C code:

 

TD1 *error;
LVRefNum *connectionid;

The new function call is:

 

callout_connect(addr, connectionid, error);

The next VI becomes:

 

callout_5.png

 

With the function call:

 

callout_receive(connectionid, error, data, 5000);

 

And finally:

 

callout_6.png

 

With the function call:

 

callout_close(addr, connectionid, error);

 

Needless to say, splitting up the VI into three separate entities has not worked so far. It compiles, sets up a connection, but somewhere the connection is then lost.

 

My suspicion is that I'm misunderstanding how the connection reference or the pointer to this reference is saved. Any suggestions?

Lars Melander
Uppsala Database Laboratory, Uppsala University
0 Kudos
Message 1 of 10
(3,298 Views)

What you are attempting to do is interesting.  Not ever doing this myself, I would say that the problem is that you are passing a pointer that points to nothing and telling LV to fill it in.  This would most likely cause your app to crash.

 

If I were doing this myself, I would not pass such things around across the boundry.  I would probably keep these simple and pass base types around.  To do this, I would for instance, pass an integer for the connection.  This would be done by using a type 1 or 2 global or a local to store the connection in an array and then index that array when the caller wants to access the connection.

 

Attached is a generic memory allocation vi that I made for things like this.

 

 

A

Message 2 of 10
(3,286 Views)

I suspect that LV is cleaning up the resources after the first call completes.

 

By uisng the first version, LV keeps the resources open.

 

I prefer the first version.

 

What don't you like about it?

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 3 of 10
(3,277 Views)
Solution
Accepted by topic author LarsM

> Not ever doing this myself, I would say that the problem is that you are passing a pointer that points to nothing and telling LV to fill it in. This would most likely cause your app to crash.

 

That was one thing I suspected too, but it didn't crash. It doesn't matter, I've solved it by putting connection and error objects in global variables. It works just fine now and seems to be the most elegant solution.

Lars Melander
Uppsala Database Laboratory, Uppsala University
0 Kudos
Message 4 of 10
(3,276 Views)

> What don't you like about it?

 

It's clumsy, short and simple. Of course, I don't know if there's any performance hit putting things in global variables, but there doesn't seem to be.

Lars Melander
Uppsala Database Laboratory, Uppsala University
0 Kudos
Message 5 of 10
(3,273 Views)

Oh, if it is not crashing, then it is probably that you are either not initialising it, but it is a global, which would by default cause it to be initialised to NULL, or you are initialising it to NULL, or it could be a random number. In all cases, LV probably has some defensive code to protect itself from accessing an object that is invalid and keep from crashing.

 

Good to hear that you got it working though.

 

 

A

0 Kudos
Message 6 of 10
(3,269 Views)

Clumys may be valid, but short and simple is usually the way to go.  🙂

 

 

A

0 Kudos
Message 7 of 10
(3,267 Views)

@O.P. wrote:

> What don't you like about it?

 

It's clumsy, short and simple. Of course, I don't know if there's any performance hit putting things in global variables, but there doesn't seem to be.


If you replace the Global with a USR (see nugget thread) and the numeric with a type-def enum you have an Action Engine (see here for Nugget on Action Engines).

 

 

Short of LVOOP, its hard to get more elegant than that.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 8 of 10
(3,266 Views)

 


O.P. wrote:   

 

In this case I try to save pointers to relevant objects in my C code:

 

TD1 *error;
LVRefNum *connectionid;

The new function call is:

 

callout_connect(addr, connectionid, error);

 

callout_receive(connectionid, error, data, 5000);

 

callout_close(addr, connectionid, error);

 

Needless to say, splitting up the VI into three separate entities has not worked so far. It compiles, sets up a connection, but somewhere the connection is then lost.

 

My suspicion is that I'm misunderstanding how the connection reference or the pointer to this reference is saved. Any suggestions?


 

Jumping in late here, but the problem is your C code.  You're allocating a pointer to connectionid (and to error, for that matter) without actually allocating any space for them.  You need to allocate those variables, then pass their address.  The C code should be:

 

TD1 error;
LVRefNum connectionid;

 

callout_connect(addr, &connectionid, &error);

 

callout_receive(&connectionid, &error, data, 5000);

 

callout_close(addr, &connectionid, &error);

 

Better still would be to have connectionid be the return value of callout_connect, which you could then pass by value (instead of by reference) to the other functions.  Note that a connection id is just a 32-bit value, so you can typecast the refnum to that type and back, just be careful that you typecast to and from the same type.

0 Kudos
Message 9 of 10
(3,234 Views)

I'm not sure about passing LV Refnums by value. Definitely not possible if you leave them as LVRefnum in the CLN configuration but I'm not sure you can configure them to be handled as ints instead.

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 10
(3,192 Views)