Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by ned

  1. You will need to provide a more detailed explanation of your problem in order for anyone to help you. It would also be good if you provide a sample text file that you are trying to read, and an example of the changes you want to make. Probably you will want to start with the Read from Spreadsheet File function, then modify the string array as desired, and finally write it back out (overwriting the old file) using Write to Spreadsheet File.
  2. No, LabVIEW will not load each DLL to find its dependencies, nor include those dependencies and check their dependencies recursively - that would quickly become a mess.
  3. This is all fine and good, but the poster specifically said that they're using a "Host-to-Target" DMA FIFO, which means the DMA FIFO Read is on the FPGA side, where it is only possible to read a single element at a time, so yes, a loop is required.
  4. What do you want to do with those 2000 elements during the 10s? Storing a 2000-element array on the FPGA in logic may not be a good use of space. Also, you can only ever read one element at a time from the DMA FIFO on the FPGA, so you'll need a loop that iterates 2000 times to read all 2000 elements. Depending on what you want to do with that data, you may want to read from the DMA FIFO into a memory block, then read values out of the memory block in a separate loop.
  5. If you post a 2012 version of your code, I'll take a look and see if I can suggest an alternate approach. If for some reason it's easier - and it might be in this case - you can pass a preallocated array, as large as the struct, in place of a cluster, then parse out sections of that array when it's returned to you.
  6. Yes, that's the right way to do it, ugly as it may look. I can't open your code (still on LabVIEW 2012 here) so I can't see exactly how you're using it, but using "Array to Cluster" with the size set to 1024 is an easy way to generate such a cluster. If you're passing filename as a separate parameter rather than an element of a struct, then you can use initialize array to generate an array of 1024 U8 instead.
  7. I'm investigating implementing a system in which plugins will implement their own set of commands. The main program will need some way to query the plugin for which commands it supports as well as the parameters and outputs from each command, and to execute those commands. Has anyone built something like this before? If so, any suggestions, warnings, or sample code to share? Initially I plan to build all the plugins as LabVIEW classes, although there's some possibility that later I will need to change it to a DLL or RPC mechanism to allow plugins to be written in other languages (I'm hoping that could be done by writing a simple LabVIEW wrapper around them).
  8. Not quite right! What you saw was a post from Rolf that said that if the struct is passed by value, then you should pass each struct member as a separate parameter. However, if you are passing the struct by reference, which is the much more common case (and the case in your function prototype), then you need to pass a single parameter representing a pointer to sufficient memory to contain the struct. Often the easiest way to do this is by defining a cluster that matches the struct definition, but you can also pass a preallocated array or string of the correct length. Passing individual struct elements will definitely not work if the function expects the struct to be passed by pointer.
  9. Again, you don't really need to poll (or you can poll really slowly). Use a very long timeout on TCP Read, at least on the client, in a separate loop, and if data arrives before the timeout then execution resumes immediately (like waiting on a notifier). On the server side, if you don't want to poll and you do need to handle multiple connections, you can dynamically launch a new VI to handle each new incoming connection. You may want to look at whether your network allows active FTP, since in that case the FTP server also establishes a connection back to the client. If the network has a rule that allows active FTP, then they may be able to add a similar rule for you (or perhaps it won't even be necessary) in which it will allow a connection from a server to a client only after establishing a connection from client to server.
  10. That sounds a lot like how standard TCP works - one side is the server, the other is the client, and once a connection is established they can communicate in both directions. To avoid polling you can do a TCP read with a forever timeout, although this can lead to situations where a connection stays open forever even though it was interrupted somewhere. Another option is to poll in a separate loop - it's not much overhead - and when a message arrives, put it in a queue (or whatever) so that there's no polling from the perspective of the rest of the code.
  11. Can you explain, in words, what the algorithm should be, even in very basic terms? Then we can talk about how you would do it in LabVIEW.
  12. What parameters do you need to measure in order to generate the data for that graph? Make a list. For each parameter, what type of sensor will you use for that measurement? Does that sensor already exist somewhere in your system? How will you get the data from the sensor into the computer? If you do not currently have any sensors and data acquisition equipment, then how will you make the measurements? We cannot tell you what equipment to purchase for this purpose, you will need to research for yourself.
  13. Does the pump in your picture connect a computer somehow? If so, using what hardware? What values can you measure on the computer? What parameters can you control from the computer? What should the graph look like when the program finishes a test? Can you create a VI that generates the right type of graph using simulated data, instead of reading it from the pump? That might be a good place to start.
  14. In what language are you trying to write your callback? You cannot do it in LabVIEW. In C# you need to create a class that implements the correct interface, and call the constructor for that class.
  15. Enqueue/Dequeue does not make a copy, so queues are a good choice here. Of course, if you enqueue data and continue to modify it at the same time, after it's already in the queue, then you'll force a copy because you'll need to have one copy in the queue and another to modify, so make sure that the wire ends at the enqueue. Preview Queue will make a copy of the data, since one copy needs to stay in the queue.
  16. In a somewhat similar situation in the past I did something like a combination of what you mention here, although in my case I was using only TCP connections. I had one loop that handled all TCP communication in both directions. Incoming data was converted to a variant, and then I added the connection refnum as an attribute of that variant. The variant went into a queue, where it could be consumed by another loop. To return a response, that consumer loop enqueued a new variant with the response data and with the same connection refnum as an attribute, so that the communication loop could send it over the correct connection. Making the connection an object obviously adds a layer of safety that I didn't have.
  17. When you say "run from Windows explorer" do you mean that the project is not open in LabVIEW, and the only VIs that are open are the one you're running and its subVIs? If so, I wonder if you have some other VI in the project that's loading a conflicting library, either a different version of a library with the same name or a different version of some dependency. If you rename the DLL, does the problem go away? What about building it into an executable?
  18. Just out of curiousity, can you build your executable with debugging enabled and see if you still get the same leak?
  19. IAsyncResult is an interface, not a concrete class, so there is no constructor for it. You need a class that implements that interface.
  20. Hi John - I was at the BALUG presentation and was awed by what you've accomplished with this code. Also, the presentation itself was well-organized. Thank you for sharing.
  21. There is a lot of material about transfer functions and Laplace transforms and precise mathematical models of the system. That's not what I meant. I meant the PID calculation itself - which is amazingly simple given how many places it can be used. I like to think about PID in terms of real units (maybe you do this already too). The Proportional gain is the ratio between a change in input and the corresponding change in output. The integral and derivative times likewise have real meanings - they're not just numbers. You likely know this already, but I'm always surprised at the number of people who have trouble explaining PID because they don't think about the physical meaning of the gains. I found that PID tuning suddenly made more sense to me when I started thinking about it the gains corresponding directly to units in the process, and it doesn't require a detailed mathematical model.
  22. In general I agree with ShaunR's comments. However, I wouldn't say that the "all you need to know" link is comprehensive. It looks like a good resource for tuning heaters and similar systems, but that's not the only application of PID. Servo controllers in motion control systems often use PID as well, but are tuned differently because they have a different response. For example, in a heating or cooling situation, you almost always need some constant output in order to maintain the desired temperature, otherwise the process starts to drift towards ambient. However, in motion control, once you reach your target, you shut off the output (or reduce the power dramatically to a holding current). If you have a slight offset from the target position, you may not want to correct it with integral control, because integral control can cause a sudden jump after the system appears to have stopped (the output will increase slowly until it's sufficient to cause motion, and then probably overshoot the target location). Servos are often tuned with proportional and derivative control alone. I don't think PID tuning is as much intuition as it is getting a feel for the effect of different gains, although maybe that feels like intuition after a while. Try setting up some simple simulated processes in LabVIEW and then tuning them. Studying the math behind it can help, too. For simple systems like heaters, where the response is generally slow, the feedback isn't noisy, and it's difficult to drive the system to instability, a basic understanding of PID equations is enough. If you're working in systems that can go unstable (and potentially cause damage), you may want to study the math in more detail, looking at stability criteria, frequency response and Bode plots. Unfortunately I can't offer a good resource on those topics, it's one of those things that I would love to understand in more depth but haven't had the right combination of need and opportunity to learn it.
  23. You're going to have to understand C pointers if you ever want this to work. The concept is simple: a pointer is a integer that contains a memory address. In a struct, a pointer takes up only the amount of space necessary to store that integer. You then need to allocate space somewhere else, initialize it with some value, and update the pointer to point at it. The size of the struct remains the same regardless of whether it contains a pointer to an empty string, or a pointer to a really long string, because the struct itself contains only the pointer. This should answer your question about whether you need to include the string lengths in calculating the buffer size.
  24. You have a misunderstanding about C. When you create "var" inside myfunction, you are allocating memory space for a new Cluster. The assignment to var, "var = (*parameters)->Variable[0];" copies the contents of the parameter into var. Then you modify the value of Type within that new copy of var and the original is left unchanged. It's doing exactly what's expected. Edit: note, however, that if you were to modify one of the strings within Var, it would be reflected in the original, because those are pointer types. The Type field is a value, not a pointer, so your function has two copies of it - one in the parameter, and another in var.
  25. Is State a class, containing all the relevant context? My first thought is a queue containing the State class, so that you can put any child state in it. That should make it easy to stack up states to which you might need to return, or to flush that list of states if you discover that you do not need to return to them. I don't know if this works in your architecture, though.
  • Create New...

Important Information

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