Jump to content

Communicating between Windows virtual memory and myRIO FPGA


Calorified

Recommended Posts

Alrighty. It's been a lot of effort trying to get around this but no luck. I have setup the following attachment on my system and myRIO (_https://decibel.ni.com/content/docs/DOC-9893).

I am presently using the kinect Face Tracking Basics WPF c# program to track a manikin head and extract z-coordinates which represent the distance of the camera from the manikin head. At present, I am writing this coordinates to memory using the memorystream method in c#.

The problem is I want to send the z-coordinates to the fpga on myRIO using the Host to Target scope in the link above. So far, I can't figure out how to do that. 

Is it even possible for labview to access physical memory on my windows computer?

I look forward to your replies.

Thank you!

DMA FIFO Code.zip

Link to comment

Alrighty. It's been a lot of effort trying to get around this but no luck. I have setup the following attachment on my system and myRIO (_https://decibel.ni.com/content/docs/DOC-9893).

I am presently using the kinect Face Tracking Basics WPF c# program to track a manikin head and extract z-coordinates which represent the distance of the camera from the manikin head. At present, I am writing this coordinates to memory using the memorystream method in c#.

The problem is I want to send the z-coordinates to the fpga on myRIO using the Host to Target scope in the link above. So far, I can't figure out how to do that. 

Is it even possible for labview to access physical memory on my windows computer?

I look forward to your replies.

Thank you!

 

Physical memory access is something you can't do on any modern OS without intervention through kernel device drivers. The entire physical memory access is highly protected from user space applications, and not just to pester users but to protect them.

 

Also the term physical memory address is pretty unclear when you talk about external hardware resources that get mapped into the system memory through techniques like PCI or similar. The resources are typically allocated and assigned dynamically at discovery time (almost anything is nowadays plug and play hardware), which makes it completely unreliable to use fixed addresses even if you can access them through some device driver. You need additional functionality to discover and enumerate the hardware in question before use and query its current hardware addresses which can change with every boot or even plug and play event.

  • Like 1
Link to comment
The problem is I want to send the z-coordinates to the fpga on myRIO using the Host to Target scope in the link above. So far, I can't figure out how to do that. 

Is it even possible for labview to access physical memory on my windows computer?

Let's clarify "Host" and "Target" here. Your myRIO is running a Real-Time operating system; that's considered the "Host." It also contains an FPGA; that's the "Target." If the myRIO supports it, you can also connect directly from the Windows machine to the FPGA, bypassing the Real-Time system, in which case the Windows computer is the "Host" and all FPGA communication between the host and target goes over Ethernet, which is a bit slower. I believe, but don't have a way to test or confirm, that you can still use a DMA FIFO on a remote FPGA target. However, if you are using the Real-Time portion of the myRIO, then the host-to-target DMA FIFO will transfer data from the Real-Time system to the FPGA, and you'll need some other way (such as TCP or UDP) to send data from the Windows computer to the myRIO.

  • Like 1
Link to comment

I would push the data from C# to LV using UDP or TCP/IP. It should be quite fast.

You have an example that can guide?

 

Also the term physical memory address is pretty unclear when you talk about external hardware resources that get mapped into the system memory through techniques like PCI or similar. 

I am using MappedMemoryFile method in C#, 

 

The resources are typically allocated and assigned dynamically at discovery time (almost anything is nowadays plug and play hardware), which makes it completely unreliable to use fixed addresses even if you can access them through some device driver. You need additional functionality to discover and enumerate the hardware in question before use and query its current hardware addresses which can change with every boot or even plug and play event.

You are right,it's been a big pain working with memory allocation over the past few days. Is there some way to work around this? I executed my c# code using mapped memory functionality and I got it to map a section of memory for writing the data I want. The question is how to dereference the pointer in Labview. I could send you my code if you do not mind.

 

...in which case the Windows computer is the "Host" and all FPGA communication between the host and target goes over Ethernet, which is a bit slower...

I am not sure if this is entirely true. Go look through the documentation for DMA/FIFO on the labview zone pages and clear this. You don't have to go over ethernet to communicate with the myRIO either. With correct memory mapping (_http://www.abhisheksur.com/2012/02/inter-process-communication-using.html) or "Named Pipe (_http://msdn.microsoft.com/en-us/library/bb546085(v=vs.110).aspx)", or WCF Interprocess Communication (_http://tech.pro/tutorial/855/wcf-tutorial-basic-interprocess-communication), I believe communication can be bridged.

Link to comment

I am using MappedMemoryFile method in C#, 

 

Ah. This is a completely different beast to DMA (Host to Target). Here is a LV version of memory mapped files (for windows) which will enable you to speak with your C# MMF in LV. You will be no closer to getting it into a myRIO, although you could replace the OS calls with those for the linux mmap if it's supported..

Link to comment

Ah. This is a completely different beast to DMA (Host to Target). Here is a LV version of memory mapped files (for windows) which will enable you to speak with your C# MMF in LV. You will be no closer to getting it into a myRIO, although you could replace the OS calls with those for the linux mmap if it's supported..

First of all, I want to thank you for this wonderful resource. You are a life-saver! Do you have some documentation on how I can use the MMap API you have shared?

I am assuming I would need to raise an event handler whenever coordinates are written to the mapped file and then use the MMap API you have sent to intercept such messages. I have the whole c# code working.

I've never done this in labview before. If you do not mind, I could send you my C# ode so you can best understand what I am trying to do in labview.

Thanks!

Edited by Calorified
Link to comment

First of all, I want to thank you for this wonderful resource. You are a life-saver! Do you have some documentation on how I can use the MMap API you have shared?

I am assuming I would need to raise an event handler whenever coordinates are written to the mapped file and then use the MMap API you have sent to intercept such messages. I have the whole c# code working.

I've never done this in labview before. If you do not mind, I could send you my C# ode so you can best understand what I am trying to do in labview.

Thanks!

 

Don't go sending nasty text stuff to me (I can only read pictures) :D There are examples of how to use the VIs for the two modes of operation (memory and files) and some details in the "context help". That's it for the docs :P.

 

The secret ingredient you may need is PostLVUserEvent to address signaling from your C# module. I know little about C# apart from it's basically .NET (which I vehemently avoid as much as much as ActiveX) so you may be able to use a .NET callback instead if you compile it as an assembly. However, if you are going to do that then why bother with memory mapped files?

Edited by ShaunR
  • Like 1
Link to comment

The secret ingredient you may need is PostLVUserEvent to address signaling from your C# module.

Thanks. One thing that confuses me about the PostUserEvent is that it seems I have to generate a signalling event from within my C# code for LabVIEW. Am I right? Or do I just go ahead in labview and generate the PostLVUserEvent without signalling the communication from C#? I looked to the MSDN documentation but this is not so elegantly explained.

 

Looking forward to reading from you.

Edited by Calorified
Link to comment

Thanks. One thing that confuses me about the PostUserEvent is that it seems I have to generate a signalling event from within my C# code for LabVIEW. Am I right? Or do I just go ahead in labview and generate the PostLVUserEvent without signalling the communication from C#? I looked to the MSDN documentation 

 

Looking forward to reading from you.

 

Yes you signal the event from your C# to LabVIEW, however to do that you will have to link dynamically to the LabVIEW.exe (or lvrt.dll for build executables or lvrtf.dll for special builds) and treat it as unmanaged API. But that poses the question why even bother about virtual/shared memory when you have an event that could carry the data anyhow.

 

Calling of PostLVUserEvent() from within LabVIEW, while in principle possible, is simply the Rube Goldberg variant of using a "Generate User Event" node in your code. 

Link to comment

... to do that you will have to link dynamically to the LabVIEW.exe (or lvrt.dll for build executables or lvrtf.dll for special builds) and treat it as unmanaged API.

I have not done this before in C#. You have a link or example that can guide?

 

 

But that poses the question why even bother about virtual/shared memory when you have an event that could carry the data anyhow.

I was trying Mapped Memory cause I felt it was the best I could do without having to write some signalling code which I am not so good at.

Link to comment

I have not done this before in C#. 

 

 

I'm going to go out on a limb here and make a wild assumption.

 

You are trying to use the skeleton face tracking, right? So, because there is a C# example, you coded that up and got it working. Now you have some C# code that gets data from the SDK API, but want to get it into LabVIEW somehow. Am I close?

 

Well. I think you have made things a little bit hard for yourself because you used C#. LabVIEW can interface directly with the API and you can use the callback function (.NET callback) to get the data into LabVIEW directly without jumping through hoops. The issue is you have isolated the data in your own monolithic program and now have to use some tricks that are quite advanced to get from there into LabVIEW. So you either write some C# code to re-transmit the events through your code to LabVIEW (which we have talked about, but isn't trivial)  or just access the events directly and not bother with the C#.

 

The SDK has the event KinectSensor.AllFramesReadyEvent. You should be able to hook that directly with the .NET callback and therefore you don't need to write your own events or messages in C# for LabVIEW (there are examples shipped with LabVIEW for demonstrating the callback - NET Event Callback for Calendar Control VI in  \examples\comm\dotnet\Events.llb and NET Event Callback for DataWatcher VI in labview\examples\comm\dotnet\Events.llb).

Edited by ShaunR
  • Like 1
Link to comment

You are entirely right except that I have the skeleton mode disabled because I am tracking an inanimate object here; this enables the kinect sensor to be able to track objects of similar facsimile as a human being. Now, this was a ton of work in C#.
In any case, I tried your suggestion on the AllFramesReadyEvent event in LabVIEW but it has no constructor. Even if it has, I would have to start putting all the code together to generate the coordinates I want from scratch. It took me a while to get here.

I just need to get this done before it's too late or I am bananas.

Link to comment

You are entirely right except that I have the skeleton mode disabled because I am tracking an inanimate object here; this enables the kinect sensor to be able to track objects of similar facsimile as a human being. Now, this was a ton of work in C#.

In any case, I tried your suggestion on the AllFramesReadyEvent event in LabVIEW but it has no constructor. Even if it has, I would have to start putting all the code together to generate the coordinates I want from scratch. It took me a while to get here.

I just need to get this done before it's too late or I am bananas.

 

Events (or listeners) don't have constructors.

 

It's a bit of a shame you have invested so much in C#. You could have just used this which probably does a lot of what you want. At least it could show you how to interface to it as a kind of tutorial.

 

Ultimately you are going to hit a brick wall, though. .NET doesn't run on myRIO (Linux Real Time)

Edited by ShaunR
Link to comment

Ultimately you are going to hit a brick wall, though. .NET doesn't run on myRIO (Linux Real Time)

Thanks. I do not need .NET on myRIO anyways. The DMA FIFO Code I showed earlier answers this part of the question. Once I can do interprocess communication from C# to labview, the Windows Host VI in the DMA FIFO Code you see at the top of the page where it's attached as a Zipped file, would move whatever data is being passed to the Windows Host VI (this exists under MY Computer Tab in the project file) to the myRIO (correct me if I am wrong). I have actually copied random data to myRIO using the Windows Host VI using the DMA FIFO Code so I feel quite positive this is possible (at least theoretically for now :P).

 

Now back to the Memory Mapped File API, I see from the example that you had to "create" then "write" to a file before the "Read" polymorphic node was invoked.

Do you think your MMAp Open can open a file that is in memory? The file in memory in this case would be from my C# code. I tried to do this earlier in the afternoon but I was getting some kind of weird error that labview doesn't seem to have a clue about: " Error -80002 occurred at Unable To Open Map

in

 MMap.lvclass:MMAP Open Map.vi

 

I would be glad to read from you.

 

Once again, thank you!

Edited by Calorified
Link to comment

I am not sure if this is entirely true. Go look through the documentation for DMA/FIFO on the labview zone pages and clear this. You don't have to go over ethernet to communicate with the myRIO either. With correct memory mapping (_http://www.abhisheksur.com/2012/02/inter-process-communication-using.html) or "Named Pipe (_http://msdn.microsoft.com/en-us/library/bb546085(v=vs.110).aspx)", or WCF Interprocess Communication (_http://tech.pro/tutorial/855/wcf-tutorial-basic-interprocess-communication), I believe communication can be bridged.

My apologies for the confusion. I believe my comments were accurate for other self-contained RIO devices (such as the cRIO); I haven't worked with a myRIO and didn't realize it has a USB interface. That said, as others have already explained, there's no way for the myRIO's FPGA and your C# code to share memory directly, nor can your C# code write directly to the DMA buffer.

 

Sounds like others already have you pointed in the right direction on this.

Link to comment

Thanks. I do not need .NET on myRIO anyways. The DMA FIFO Code I showed earlier answers this part of the question. Once I can do interprocess communication from C# to labview, the Windows Host VI in the DMA FIFO Code you see at the top of the page where it's attached as a Zipped file, would move whatever data is being passed to the Windows Host VI (this exists under MY Computer Tab in the project file) to the myRIO (correct me if I am wrong). I have actually copied random data to myRIO using the Windows Host VI using the DMA FIFO Code so I feel quite positive this is possible (at least theoretically for now :P).

Yes. I think you will be a little surprised when you come to do this as it probably isn't doing what you think it is (as Ned is trying to explain).  ;) 

 

Now back to the Memory Mapped File API, I see from the example that you had to "create" then "write" to a file before the "Read" polymorphic node was invoked.

Do you think your MMAp Open can open a file that is in memory? The file in memory in this case would be from my C# code. I tried to do this earlier in the afternoon but I was getting some kind of weird error that labview doesn't seem to have a clue about: " Error -80002 occurred at Unable To Open Map

in

 MMap.lvclass:MMAP Open Map.vi

Yes. It creates and then writes because you need something to read otherwise it would be an empty string or error (there is no CreateOrOpen equivalent).

...And Yes.

"Open" is equivalent to OpenExisting(string mapName) in C#. Similarly, "Create File Map" is equivalent to CreateFromFile(String, FileMode, String, Int64) - I think they term it "persistent" mapping. Likewise, Create Memory Map equates to CreateNew(String, Int64, MemoryMappedFileAccess) which I think they term Non-Persistent mapping . I think that's right at least. The VIs use the windows API rather than .NET so the call names are bit different.

So you'll create your file map in your C# probably using "CreateNew" with READ/WRITE permissions and a certain mapName (it doesn't have to be persistent and on disk) and then you'll "Open" it in LabVIEW (with READ permission) with whatever "mapName" string you gave it in the C# CreateNew method.

 

Error -80002 just means it couldn't open a mapping either because a map with that name doesn't exist or because it doesn't have the permission to open it.

Edited by ShaunR
  • Like 1
Link to comment

Alrighty. Here's the C# snippet I have:

int n = 121;

foreach (Vector3DF[] vector in facePoints3D.GetSlices(n))

{

var copier = new VectorSerializer();

//act

byte[] bytearray = copier.SerializeVectors(vector);

Vector3DF[] copiedVectors = copier.DeserializeVectors(bytearray);

//Initialize unmanaged memory to hold array.

int size = Marshal.SizeOf(bytearray[0]) * bytearray.Length;

IntPtr pnt = Marshal.AllocHGlobal(size);

//bool mutexCreated;

// Mutex mutex = new Mutex(true, "vectmapmutex", out mutexCreated);

//copy the array to unmanaged memory.

Marshal.Copy(bytearray, 0, pnt, bytearray.Length);

// Copy the unmanaged array back to another managed array.

byte[] bytearray2 = new byte[bytearray.Length];

Marshal.Copy(pnt, bytearray2, 0, bytearray.Length);

//Console.WriteLine("The array was coppied to unmanaged memory and back.");

try

{

using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("vectmap", 1024 * 1024))

{

//bool mutexCreated;

//Mutex mutex = new Mutex(true, "vectmapmutex", out mutexCreated);

//Copy to Memory Mapped File

using (MemoryMappedViewStream mapstream = mmf.CreateViewStream())

{

BinaryWriter binwriter = new BinaryWriter(mapstream);

binwriter.Write(bytearray2);

}

// mutex.ReleaseMutex();

//mutex.WaitOne(1000);

using (MemoryMappedViewStream mapstream = mmf.CreateViewStream())

{

BinaryReader binreader = new BinaryReader(mapstream);

//return binreader.ReadBytes((int)mapstream.Length);

Console.WriteLine("vectors: {0}", binreader.ReadBoolean());

}

// mutex.ReleaseMutex();

}

}

finally

{

// Free the unmanaged memory.

Marshal.FreeHGlobal(pnt);

}

Console.WriteLine(string.Join(",", bytearray2));

// sw.WriteLine(string.Join(",", bytearray));

//sw.Flush();

stream.Position = 0; // so we can read from file beginning, set stream position to null

} // close memorystream thread

} // close foreach thread

I tested the C# code earlier and it works fine except for the mutex part of the code which was throwing a synchronization thread exception (which I guess I have to figure out somehow later. To save the day, I have commented this out of the code for now).

And in labview, I have the following: post-53076-0-19499500-1420436780_thumb.p

I am not at work now as I am working from home.

I will deploy this when I get to the lab tomorrow morning and I better hope it works.

Thanks for your help ShaunR, Rolf and every other one person that has contributed to my learning. If you think there is any modification I need to add into my code, kindly let me know. Thanks once again.

Link to comment

"Open" is equivalent to OpenExisting(string mapName) in C#. Similarly, "Create File Map" is equivalent to CreateFromFile(String, FileMode, String, Int64) - I think they term it "persistent" mapping. Likewise, Create Memory Map equates to CreateNew(String, Int64, MemoryMappedFileAccess) which I think they term Non-Persistent mapping . I think that's right at least. The VIs use the windows API rather than .NET so the call names are bit different.

So you'll create your file map in your C# probably using "CreateNew" with READ/WRITE permissions and a certain mapName (it doesn't have to be persistent and on disk) and then you'll "Open" it in LabVIEW (with READ permission) with whatever "mapName" string you gave it in the C# CreateNew method.

 

Error -80002 just means it couldn't open a mapping either because a map with that name doesn't exist or because it doesn't have the permission to open it.

I did the above and I still have the same error. I am officially depressed! :(

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.