Jump to content

C# DLL 'asking' for values from LV


Recommended Posts

Good morning from sunny Massachusetts, USA...

I'm doing maintenance on an image processing/laser holography application written in LV7.0. The application is structured with LV calling a C# DLL (accessed via .NET constructor and invoke) that handles the heavy lifting of manipulating pixel data and adjusting the position of a few mechanical stages. Other than the C# aka .NET assembly being a little slow to start up, this approach works fine...

...until my client, after observing the system in action, said, "That's great. Could you add one more feature, namely, every so often the C# should log the value of the laser power meter?" The problem I'm facing is the laser power reading is being acquired by the 'parent' LV program, inside a while loop, so it's continuously available, but I don't know how to 'ask' LV for the value from my C# DLL. Could the forum suggest a mechanism to accomplish this?

I'd be glad to supply any additional info that might be useful. Thanks for your help.

Regards,

John

Link to comment

...every so often the C# should log the value of the laser power meter?" The problem I'm facing is the laser power reading is being acquired by the 'parent' LV program, inside a while loop, so it's continuously available, ...

Why not have LV log the value for you?

I can't help you with the C#, but I know that you can pass a value to a C DLL and do something with it. Of course you have to have access to the C code that made the DLL and make a new function.

You'll have to have some way to determine logging frequency no matter what, once you determine its time to log the value, you would either call a function in the C# DLL or log the value with LV.

Chris

Link to comment
Good morning from sunny Massachusetts, USA...

I'm doing maintenance on an image processing/laser holography application written in LV7.0. The application is structured with LV calling a C# DLL (accessed via .NET constructor and invoke) that handles the heavy lifting of manipulating pixel data and adjusting the position of a few mechanical stages. Other than the C# aka .NET assembly being a little slow to start up, this approach works fine...

...until my client, after observing the system in action, said, "That's great. Could you add one more feature, namely, every so often the C# should log the value of the laser power meter?" The problem I'm facing is the laser power reading is being acquired by the 'parent' LV program, inside a while loop, so it's continuously available, but I don't know how to 'ask' LV for the value from my C# DLL. Could the forum suggest a mechanism to accomplish this?

I'd be glad to supply any additional info that might be useful. Thanks for your help.

Regards,

John

One of the easiest ways to do this would be to establish a TCP connection between the C# app and the LabVIEW app. Then, the LabVIEW app could listen for requests from the C# app for commands like 'GET: POWER METER VALUE' (typically, you'd wait for requests in an idle frame or in a loop that is reading the TCP buffer). The good thing about this method is its easy to scale up with more commands if the user decides they need other data from the LabVIEW app in the C# app. The downside is that there can be a lag between when the C# app requests the value and the value on the meter so if your power meter value is changing really fast and your system has timing constraints this method may not work out too well.

Link to comment

Hi Chris,

Thanks for your suggestions. I responded to a few of your points:

Why not have LV log the value for you?

<John>The subordinate C# DLL is the only code that 'knows' when it's time grab the power meter value; the parent LV just continuosly reads the power meter value.

I can't help you with the C#, but I know that you can pass a value to a C DLL and do something with it. Of course you have to have access to the C code that made the DLL and make a new function.

<John>The C# operates pretty much the same way as using a C DLL; that is, called from LV into a C# DLL. What I need is a function that calls FROM the C# TO Labview; what I have now is a bunch of methods/functions baked into a DLL that my be called FROM LabView. Hey, can I just turn my DLL upside down and have it work backwards? :headbang:

You'll have to have some way to determine logging frequency no matter what, once you determine its time to log the value, you would either call a function in the C# DLL or log the value with LV.

<John>The C# knows when to log. When that time comes, how does it initiate fetching the power meter value from LabView?

Chris

<John>I appreciate your efforts. Thanks!

Link to comment

What about a function that feeds the power meter value to the C# DLL evertime it is read in LabVIEW? Then the C# DLL will have the value, as often as the LabVIEW code does. Then the C# DLL can log it when ever it needs too. As Omar mentioned, if your power meter is changing rapidly, this might be a problem. As Omar mentioned a TCP connection would work too, although I've never used that technique.

Link to comment
What about a function that feeds the power meter value to the C# DLL evertime it is read in LabVIEW? Then the C# DLL will have the value, as often as the LabVIEW code does. Then the C# DLL can log it when ever it needs too. As Omar mentioned, if your power meter is changing rapidly, this might be a problem. As Omar mentioned a TCP connection would work too, although I've never used that technique.

I think that will work. It's not synchronous with the C#, but certainly better than no value at all! I'll try this out first thing tomorrow and report on how it worked.

Thanks for your help, hopefully one of these days I can be the helpER instead of the helpEE. :thumbup:

Best,

John

Link to comment
...until my client, after observing the system in action, said, "That's great. Could you add one more feature, namely, every so often the C# should log the value of the laser power meter?" The problem I'm facing is the laser power reading is being acquired by the 'parent' LV program, inside a while loop, so it's continuously available, but I don't know how to 'ask' LV for the value from my C# DLL. Could the forum suggest a mechanism to accomplish this?

You should use events to do the trick. Check the examples below to get an idea how you can use events to communicate between .NET and LabVIEW processes. You can either set LV to generate .NET event or you can set .NET event to to catched by LabVIEW.

labview\examples\comm\dotnet\Events.llb\NET Event Callback for Calendar Control.vi

labview\examples\comm\dotnet\Events.llb\NET Event Callback for DataWatcher.vi

Link to comment
You should use events to do the trick. Check the examples below to get an idea how you can use events to communicate between .NET and LabVIEW processes. You can either set LV to generate .NET event or you can set .NET event to to catched by LabVIEW.

labview\examples\comm\dotnet\Events.llb\NET Event Callback for Calendar Control.vi

labview\examples\comm\dotnet\Events.llb\NET Event Callback for DataWatcher.vi

This is the best idea on this list :thumbup:

Link to comment

Good morning Chris, Jimi, and Omar-

Jimi, your suggestion sounds perfect for what I need. When I went looking for the cited examples, I didn't have an 'events.llb' in my 'labview\examples\comm\dotnet\' path; instead, I have 'SimpleTaskMonitor.llb' and 'Calculator.llb'. I cracked those open and while they supply useful info on using .NET assemblies, I didn't spy anything on callbacks.

I poked around the directories, found some stuff on ActiveXEvents which might prove enlightening...but I figured I'd ask if perhaps running 7.0 is the reason my directory structure is different? Is there another source for those, or similar, examples? I've run into the case where I find a cool looking VI on the Web, only to have the dreaded 'You must have 8.x installed to run this example'. Maybe I can beat my client over the head if this is a 7/8 issue. :D

Anyway, thanks for all the help, I'm learning a ton about LabView as part of this at times painful process.

Hey Jimi, you don't play guitar by any chance, do you? :thumbup:

Best,

John

Link to comment
Jimi, your suggestion sounds perfect for what I need. When I went looking for the cited examples, I didn't have an 'events.llb' in my 'labview\examples\comm\dotnet\' path; instead, I have 'SimpleTaskMonitor.llb' and 'Calculator.llb'. I cracked those open and while they supply useful info on using .NET assemblies, I didn't spy anything on callbacks.

Ok. Check if you have the following node in your version of LabVIEW: "Register for Event Callback". This node is used to register a LabVIEW VI to be called when ever a .NET or ActiveX event is generated. When you register the callback VI, you can define which parameters are passed to this VI. If you select to pass a .NET object reference to this VI, you can then from this VI use the .NET method of that object to set the what ever value you want to pass to C# code. If your class has a method "Log" you can call this method from the callback VI and with a parameter that you want to log.

Since LabVIEW doesn't use references for normal wires, you should use some other method to pass the logged parameter to the callback VI from the main program. The alternatives are

  • You write the parameter to a queue when ever the value is updated. You pass the queue reference to the callback VI together with the .NET object reference. Then both the queue and the .NET object are accessible from the callback VI.
  • You use functional global i.e. uninitialized shift register to store the value. If you do not know about uninitialized shift registers, forget this alternative
  • You can update a front panel control in your VI for which the logged variable is local. You can pass the reference to this front panel control/indicator to the callback VI.
  • You can use global variable or shared variable. This is easy but not recommended.

I'd prefer the first or second alternative.

To pass a callback VI reference to the Register for Event Callback node, use static VI reference constant and link it to your VI by right clicking the reference and then selecting Browse for path...

EDIT: If this is too complicated, there is a simple and straight forward alternative. You call .NET code by calling a constructor for a class and maybe some other methods Well write a method for this class, something like "setValueFromLabVIEW". Wire the reference of the .NET object you created with the constructor to the loop in which you have the value you want to log. Then simply call setValeFromLabVIEW method of your .NET class. Do this by right clicking on the .NET object wire and selecting create -> Method for X.Y class. This places the method call to your LV diagram. Then you pass this method the arguments you need by wiring the arguments to the node you just created. This way your problem is transformed in to a new problem, how to access a value of my .NET object from C#. This is much more trivial to you, although it may not be trivial to most of us.

in the loop where your constant is available, use this method to set

Link to comment
...until my client, after observing the system in action, said, "That's great. Could you add one more feature, namely, every so often the C# should log the value of the laser power meter?" The problem I'm facing is the laser power reading is being acquired by the 'parent' LV program, inside a while loop, so it's continuously available, but I don't know how to 'ask' LV for the value from my C# DLL. Could the forum suggest a mechanism to accomplish this?

Add a method to your C# that is "ShouldUpdateLaserPowerReading". Have that method take zero parameters and output uInt8 for True or False.

Add a second method to your C# that is "UpdateLaserPowerReading". Have that method take one paramter -- the data.

Have LV call the first method to determine whether or not the C# wants a copy of the data at this moment. If it returns True, then call the second method. The second method should copy the data into whatever structure C# wants.

This solution avoids copying the laser power reading data (which I'm assuming is some sort of larger waveform and not just a simple double value) unless the C# is really asking for it. On the C# side of the code, set the flag that says "Yes, please update the value" and then wait (polling loop or sleep) until that flag gets cleared -- then you know that the value has been updated and the C# code can now proceed.

Link to comment
Add a method to your C# that is "ShouldUpdateLaserPowerReading". Have that method take zero parameters and output uInt8 for True or False.

Add a second method to your C# that is "UpdateLaserPowerReading". Have that method take one paramter -- the data.

Have LV call the first method to determine whether or not the C# wants a copy of the data at this moment. If it returns True, then call the second method. The second method should copy the data into whatever structure C# wants.

This solution avoids copying the laser power reading data (which I'm assuming is some sort of larger waveform and not just a simple double value) unless the C# is really asking for it. On the C# side of the code, set the flag that says "Yes, please update the value" and then wait (polling loop or sleep) until that flag gets cleared -- then you know that the value has been updated and the C# code can now proceed.

Hi Aristos,

Thanks for suggesting that method, it seems like it would work. The data is actually just a double, not a waveform, so the data size is not a problem. I want to finish the technique suggested by Jimi...using callbacks...before I try this approach. And of course since it's Monday morning here in the eastern US, someone cycled the power to whole optical table over the weekend and pretty everything is not working. :o ...engineering, you gotta love it!

Best,

John

John,

You may be out of luck, I don't believe 7.0 supported .NET. Those functions came along with 8.0. BTW, I play guitar, but I don't know if Jimi does... Still, a callback from .NET would be the easiest method, but as you have seen, not the only method of getting the job done.

Chris

Hi Chris,

As it turns out, at least my version of 7.0...something my client had before I came on the scene...is .NET capable. I've actually been doing the majority of my work on this project by building C++ and C# DLL's with usually just one method, and then using that as a portal to use some classes I've constructed in the past. I found what I needed in the Functions panel, under 'Communication'...next 'TCP' and some others. It could be that a previous engineer downloaded and installed something, if NI put that out as an option...dunno.

Given Jimi's handle, I couldn't resist asking if he was a player. :question: I hack at guitar myself.

Best,

John

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.