Jump to content

theoneandonlyjim

Members
  • Posts

    24
  • Joined

  • Last visited

Posts posted by theoneandonlyjim

  1. I think the message mediator approach is a good one. See: Mediator Pattern. I had used this for a while, thinking I was quite novel, and Daklu then told me this pattern actually has a name. Not so novel anymore :P . What's nice about this is that you can generate generic processes that just spit out messages, and then you can take care of application specific stuff in your mediator. Think, for example, of a generic TCP loop. My TCP manager that I reuse reads a fixed header and then the message data and just sticks it in a queue. It can be reused on every application. I then let my mediator decode the message as it pertains to that application and sends it where it needs to go.

    Cool. I’m not reinventing the wheel.

    Does this make sense?

    I think so, at least on the face of it. In my most recent applications, I’ve applied OOP as far as my storage type goes – Storage (parent), Access DB (child), text (potential child), etc. My present approach is to bundle new data into an application-specific cluster, which is converted into a variant before input into a dynamic dispatch “Store” method. It works because the DB queries included with LV are able to decode the variant and insert results in the proper columns. I haven’t tried another file format because of time/lack of need, but I’d like to include others as an option in upcoming revs and I don’t think I’ll be able to slide by on included software. I also was looking to extend that principle into building the specific entries – test ID, captured data, test notes, time stamp.

    Here is an example of a logger from NI's website, but admittedly, I haven't used it so I'm not sure how valuable it is. As far as I can tell, it seems like a valid example, though.

    The linked example builds its entries for the logs by flattening clusters to a string in the “Add Log” VI, then unflattening using the same control as a key in the "Write Log". It works for the example, but it seems that this approach would couple the code to the application – especially for “results” entries.

    Could I follow a similar path with a modification that I think would decrease coupling:

    · Receive results or ID information in the logger mediator

    · Convert to a string, append header information (position in the log, etc.) based on message name

    · Enqueue the converted information into the logger process

    · Dequeue and handle the information in a known way using the header information – possibly by replacing a subset in an array of strings, then rely on non-LV, application-specific tools if doing analysis or retrieval

    · Keep the in-progress handled information in logger until “Store” instruction or record is complete

    · On “Store” or complete record, perform dynamic dispatch “Store” Method

    · Revert temporary logger information to in-progress state

    Storage space could be a problem, since strings are large data types, but maybe I could figure a way to include data type in the header and decoding in the logger.

    Thanks for the quick turn.

    Edited for formatting issues.

  2. I feel I've plateaued in my approach toward data storage. I am still stuck routing data from a tool through a central mediator to a component specifically designed to manage data. My applications have had low data rates or been manually controlled, so the approach has worked, but I'd expect that a faster data rate or more components could induce lag at some point.

    Here's a reduced-scale example:

    User presses "Store Data from A" or timer expires, message is sent to mediator >> Mediator routes "Store Data from A" message to Tool A >> Tool A makes measurement, passes to mediator >> Mediator passes measurement to Data Storage >> Data is stored.

    What I am looking to do is follow this sequence:

    • Tool A generates data on a known schedule, puts it in "a place" (maybe its final location)
    • User or program synchronization makes "Store Data from A" request
    • Mediator routes message to Tool A
    • Tool A handles "Store Data from A" by storing data currently in "a place" in specified location using preferred storage method

    In effect, cutting out the data manager that has to be written or adapted in each project.

    A couple of questions, then: Am I overthinking this - trying to achieve something overly fancy? Will I be able to make a method of data storage generic enough that I stay uncoupled? If the answer to these are no and yes, what architecture might one use to accomplish the goal of a decentralized, but still synchronized data manager? If possible, I would welcome links to any KB or other article that would move me forward.

    Thanks in advance,

    Jim

  3. We have suffered similar issues with our plugin-based application using packed project libraries. Any time we loaded more than one packed library that called the same "inlined" VI (say for instance, a VI in our reuse library) as another loaded packed library, it would break with a similar message. Individually they loaded fine. In the end we just turned off the inline feature on the reuse code and all was well.

    We haven't yet got around to thoroughly investigating and reporting the issue, but I might suggest experimenting with removing the inline settings and trying again.

    Unchecking "Inline" throughout the project did the trick. Thanks.

    I guess I have some learning to do about to what level I can use that option. Accessors only? Small operations like array indexing, adding, comparison? I'll look on LAVA and NI, but any insight is welcome.

    These issues can be really tough to debug.

    Agreed. The debug tool wouldn't connect and generated an access violation, so I was left with forum and Google crawls.

    I considered that it was reentrancy, but didn't think of inlining. When the VI got stripped to little more than an event structure, initialization code, and empty while loops and the EXE was still broken, I thought something was wrong with one of my classes. I got stuck on "Well, if it's because the VIs are reentrant, the solution is going to be code duplication, and that's not what I want."

    You may not have explicitly included external dependencies or done any dynamic loading, however are you sure the emulators don't do as much? Or other code you may use?

    One trick you can play is this: open your LabVIEW project and look at your Dependencies. If you don't see the dependencies in the project explorer, make sure the menu item Project: Filter View: Dependencies is checked.

    There you should see anything that your project uses which isn't explicitly included in your project. You can probably ignore the things in user.lib and vi.lib, but you may also see things like some DLLs or .NET assembly references here that need to be brought into the project.

    If you find dependencies, is it a system-level library? Stuff like kernel32.dll, or other Windows components. Chances are you won't need to worry about these, although they may restrict which operating systems you can use your executable on. If it's not a system-level dependency, make sure it gets included in your build. LabVIEW will usually pull any of these into a build automatically, but dynamic loading can leave no clear traceable path to them and easily result in them not being picked up when building.

    I wasn't clear on this before, either. What can I leave in dependencies? Some of the classes explicitly contained in the project have parents that weren't. There was some reuse code in dependencies, too. I've moved all but the instr.lib, user.lib, and vi.lib into the project just to be safe, but I thought the build would capture them.

    This experience shows me that I should shore up my knowledge on app builds. I've run most of my projects in the dev environment and this was the first where I've tried to make a serious attempt at a formal app build.

    Thank you both.

  4. As part of my latest debug process, I've been building EXEs with a basic test platform and the necessary support files - hopefully cutting down on places to look for problems in each component.

    The test platform in each case is a basic UI where I can enqueue messages (start, stop, do something) or receive messages (data, status, errors) plus the control code I want to trace. I've been successful with debugging and building several components (temperature readout and calculations, stage control, voltage measurement), but have hit a wall with building the last (a pair of power supplies). I have changed no settings from build to build.

    For all components, I can do what I want in the development environment. With most, I can build and get the same expected function. With the power supplies, I can do what I want in dev, However, the build completes without error, but the EXE is broken. I get a "The VI is not executable. The full development..." error. The major difference that I'm able to discern is that the power supply test platform has reentrant VIs (some are inlined). Since I'm using OOP and dynamic dispatch, they're sharing clones. If I put a "diagram disable" box around the top level VI for one of the supplies, the app builds and runs successfully, albeit with only one supply functioning.

    I've looked on the web and the causes I've been able to find for the error aren't relevant for my test. I'm using an emulator for the supplies (no drivers), I'm not dynamically loading anything (path name failures don't happen), and there are no DLLs (I'm not that good yet). Has anyone else run into problems with this? Why wouldn't the error appear in the build process?

    I'm running LV2011.

  5. There is no performance impact from the depth or breadth of a dynamic dispatch hierarchy. The time needed to dispatch to the correct implementation is constant regardless of the number of classes in memory, the number of methods that a given class has or the number of overrides for a particular method.

    Excellent. I'll leave it alone.

    Thank you.

  6. OK - I think I'm on my way to figuring this out, but I have a more specific question I hope will generate an answer.

    If I pursue this course of action, one of the "Choose Implementation" windows looks like the attachment.

    It seems like I leave myself open to slowdown as a result of the large dynamic dispatch tree the project would have to navigate through. Am I right in this thought?

    If so, to break it into smaller trees seems like it would require duplicates of the more basic methods that each parent class would have, since their class data would be very similar. This would lead to longer dev time and a larger project. Is this right and would that be this a bigger issue than the potential slowdown?

    [Edited to include attachment]

    post-17061-0-46787500-1345996213_thumb.j

  7. I've started a project as a way of transitioning from task-based to object-oriented programming. So far, I wish I'd put the effort in sooner. OOP solves a lot of problems I spent frustrating hours considering ways to get around.

    Platitudes aside, I want to make sure I'm making the right choices as I learn, so that the right practices are in place beginning early in the process. I favor a hierarchical architecture similar to what's been discussed in other topics on the board, and an observation I've made as I write is that much of the code falls into two categories: abstraction layers and mediators.

    There are both general similarities (queues in and out, auto/manual mode, etc.) and functional differences (power supply vs. multimeter vs. stepper motor), which spawned a thought and a series of questions. I'm considering building a class for a parent abstraction layer and/or a class for a parent mediator, then inheriting as needed. What pitfalls or advantages might I have missed? Will I discover as my skills progress that I've imposed a need for work-arounds? Or, if I'm careful to keep the parent classes away from anything application-specific, will it provide a good base to my coding that can be managed by version control?

  8. Thanks for the illustration. It generated some additional questions for me. I'll admit I don't have a CS background, so please excuse any ignorance I show.

    When you say "don't know the specific VI at compile time", do you mean that I have (for example) three subVIs, and based on the input used to choose my plugin, I load the correct one? Or, do you mean that I'm leaving a placeholder for a VI with this specific connector pane that I haven't written yet? If it requires inclusion in my build, how is this an advantage over standard subVIs?

    If I'm not including VIs in my "always included" list for the executable build, they need to be part of the installer build so that they're placed at a location identified by the path within the caller VI, right?

    I think dynamic loading/launching is what I am after. The application calls for controlling one of three pre-defined tests sharing a common set of equipment. I want to mask user input because, though there are commonalities between the three tests, not all use all the equipment. I want to load only the components needed.

  9. Please define the term "dynamic VIs" ... are you talking "VIs that you load dynamically using Open VI Reference or the 'Call Setup' pop up menu option on a subVI node" or are you talking about "dynamic dispatch VIs that are members of LabVIEW classes"?

    The answer to your questions will vary greatly depending upon which of these two technologies you're asking about.

    Sorry - I meant dynamically loaded VIs using Open VI Reference. OOP is something I've yet to tackle.

  10. I'm kind of new to the use of dynamic subVIs, but I've come to recognize just how powerful they can be. I'm revising some existing code and really want to implement them.

    Before I make them a part of the project, I've been working smaller examples scratch-pad style to get my head around a couple of concepts. I've been able to develop a main and sub-vi example that I've successfully built into an application.

    While doing so, I've come up with a couple of questions. I'll throw them out to the 'net and see what I get back.

    -For diagram clarity/readability, I intend to use subVIs within the dynamic VIs. Are these loaded/unloaded as part of the dynamic code?

    -Along those lines, what happens when I build my application? Do I list the subVIs within the dynamic VIs under "Always Included"? Do I even have to include the dynamic VIs? What about source file settings? I could see that as getting complicated if my application grew past a certain point.

    -Is there a good VI or other program that allows one to monitor built application memory usage (running/loaded EXEs, VIs, etc.), similar to what "Dynamically Monitor VIs" can do in the development regime? Tracking program function might answer these and other questions I might have.

    I recognize that these are basic questions, but this topic has just not sunk in for me yet. Apologies also if this is the wrong forum.

  11. I've been working on a bug for sometime now.

    On two separate Windows systems (one XP and another Vista), I've run into a situation where I temporarily lose connection to a tool connected by USB - just long enough to throw an error in the code and stop the program. I have been thus far unable to figure out a set of conditions which induces this failure, which appears at irregular intervals: 700+ hours, 400+ hours, 48 hours after test start. This has now happened with a two different GPIB-USB and SCXI-1600 connected by USB.

    I've been told (and observed) two things: that occasionally Windows will selectively suspend USB inputs to conserve power or that the USB inputs will compete for resources. I have observed one tool to be unresponsive to *IDN queries until restart and another to be perfectly healthy when investigated.

    As such, I've tried a couple of things:

    -Edited the registry to disable selective suspend - the failure's happened once since then, but there are more "USB" prefixed keys in the registry - should I disable them all?

    -Added a separate USB card so that my tools aren't sharing resources with the mouse and keyboard - the failure has happened multiple times since then

    -Disabled all hibernation, sleep, and power off options

    A couple more were suggested by NI:

    -Reset Resource VI - I have yet to get the example VI in LV10 to work.

    -Changing to Windows 7

    -Making connections with a GPIB-GPIB - not only is this out of budget, but it doesn't help for the SCXI

    I've thought of another:

    -Cutting the USB cable open, clipping the +5 VDC and putting each side on two halves of an SPDT switch connected by RS232 - effectively unplugging/plugging the cable as a manual reset.

    Since this is such an irregular error (and sometimes leads to thermal runaway), I'd like to apply as many backup solutions as I can before I commit more samples. Has anyone else had this error, and if so, did you try anything different?

  12. Some things I noticed:

    1. The only flow control on that loop is waiting for the read. You could use an event structure and a DAQmx event to potentially improve your response. A good one to use is EveryNSamplesAcqIntoBuffer.

    2. You are doing some unknown amount of processing in that state. You might try using a producer/consumer architecture so that the processing and database access don't potentially slow your loop down.

    3. What is that DataQ and what is putting data in there? That state won't run if the queue is empty.

    4. You have the task set up for 100 samples per channel, yet your read is for 1 sample per channel.

    Try checking some of those things. If you narrow down the delay to the actual DAQ read, then I think a call to NI would be a good bet. There are cases where the hardware acts weird, but you have to eliminate the software first.

    Are you using Legacy DAQ somewhere else in your code?

    I had code that mixed DAQ and DAQmx and saw a similar behavior to what you are seeing. NI confirmed this was caused by Legacy DAQ.

    I only need temp at that specific point in the loop, so I was trying to economize with my loops. I didn't think I needed to monitor T throughout and pick off at needed times, but it seems like the overhead involved with the "Start Task -> Take Measurement -> Shutdown Task" is throwing my timing out of sync. I'll try producer/consumer where I pass a current value from loop to loop, but there seems like something easier that I'm missing.

  13. Thanks everyone.

    Where are you located?

    Live in Raleigh, work in Durham, NC

    Jim,

    Yes, NI does have user groups in some areas. Best way to find out if any are around you is to call your local sales reps.

    I hadn't thought of that. I'd better polish my "No, thank you, I'm all set on new hardware" speech.

    Jim

    I am pretty isolated wrt LabVIEW and I have found nothing beats online resources, in particular LAVA. There are a wealth of really talented people that will give you help and advice as long as you put the effort in too. There is also a repo full of good stuff, not to mention histories of posts that may have already answered your questions.

    Sure, i'd kill for a mentor, but if you don't get one don't freak out.

    LAVA's been great for specific stuff, but I'm thinking more in the abstract. I don't always have a question, but I always need to learn. Like crelf suggests, I want someone better, whose code I can look at in an idle moment and say, "That's a great way to do that." Maybe I can drift around LAVA when I have that urge.

    I've found the best mentors as those you work beside - there's something to be said for working with people that are better than you: you're always challenged, and it's the best way to improve. So, looking for a mentor is a good idea, but looking for a company that is full of mentors is even better!

    I've been thinking of a change, maybe it's time.

    Thanks for the segway Chris!

    Data Science Automation is hiring now. We were started by the first person outside NI certified as a CPI, are lead by the 5Th CLA in the world, have two resident LabVIEW Champions and have one of the highest concenttations of of CLA's you can find anywhere.

    Interested parties should check out

    DSAutomation.com

    for more information.

    But on second thought, maybe that is not what Chris was hinting at.

    :rolleyes:

    Ben

    Any chance of a Raleigh branch opening?

  14. Not specifically from this board, necessarily, but I'm looking for ways to build my skills. I'm the only person who uses the language at my company and I get around well enough to run our test sector, but if I'm going to move up or on, I need to get better.

    Does NI sponsor user groups? Are there real-world LAVA lounges? Any pointers in the right direction are appreciated. Thanks.

  15. I'm running into a synchronization issue with an SCXI-1112 in an SCXI-1000 frame. Irregularly (every 10 to 15 reads), the read takes roughly 10x longer than the majority of the reads. This slows the rest of that case down, which drops data. I've tried various sample sizes, changing my loop delay, and adding "DAQ Control Task" in my initialization to set the task into "Commit". What else might I try to polish the edges so it doesn't stick any more? I've attached pictures of the relevant code.

    post-17061-0-86090400-1297630639_thumb.j

  16. Some exposition before the question:

    I'm trying to restrict access to a tool using semaphores.

    In my top-level vi, I obtain the reference during my "Initialize" state and release it in my "Stop" state. The reference is untouched in any other state and resides in a shift register. When I pull the reference from the shift register, the "Release Reference" vi generates an error, saying the reference is invalid. I'm only to the point of testing my top-level VI, so no other manipulation occurs.

    When instead I obtain the reference before my state machine loop begins (initializing the shift register), I don't get this error. I might be having a mental block, but it's not clear to me what the difference is between the two styles. What am I missing?

  17. In my opinion, yes! It would change your approach a bit, but if you were willing to use Object-Oriented design patterns you could use a combination of the Command Pattern (in particular, you could include the target controller as an object inside the command, thus handling all commands for all controllers through a single--preferably asynchronous--message channel) and the State Pattern. You can create a Controller class and then create subclasses that inherit from this.

    Ah, and there's the rub. I'm just now getting into LabVIEW OOP, and my skills aren't quite up to this level of a challenge. Maybe in a future rev. Thanks.

  18. I've got to communicate dynamically with several stations which carry out essentially the same operations, where the parameters are individually input by UI and operation by semaphore-controlled tool function.

    Right now I've got the project set up as a QSM as seen in the attached photo.

    post-17061-127309127475_thumb.jpg

    The top level VI initializes itself, the subVIs and then is idle while the subVIs operate unless an error or stop command is passed. I find myself saving each subVI as a unique file in order to maintain operation of the state machine for each, rather than what seems logical - to place a single reentrant VI. This brings to light my question - is there a better option than a QSM?

  19. Sorry for the double post, but I realized last night that I was pretty vague in what I was after.

    I have a framework for the individual pieces (collecting/adjusting temperature, collecting/adjusting voltage), but there needs to be some interaction between the collect/adjust loops in addition to displaying the values on the front panel and writing the data to the server. Right now the method is a complicated set of local variables, and I'd like to move away from that because it's been difficult to debug. If it was one stage, I think I'd be in business, but I'm having trouble wrapping my head around how to pass and process the data for each stage in a clean way.

    Let's try this again.

    I am attempting to write software to accomplish the following:

    -Acquire, control and display on front panel temperature read in from DAQ

    -Acquire, control and display on front panel voltage and current

    Each of these individual functions works independently. I have six individual stages and my application requires me to have control of each of these inputs and outputs through a state machine.

    Two temperature measurements are important for each of the stages: below and above the device under test. When current is applied to the device, the temperature above changes with relation to the current.

    I've defined the state machine to be:

    -Initialize

    -Find maximum temperature difference with relation to current between two points on the device, adjust current accordingly

    -Adjust stage temperature to input target

    -Find maximum temperature difference with relation to current between two points on the device, adjust current accordingly

    -Cycle current on and off until user stops operation- subsequence of states: wait cycle time, increment cycles, write to log file, toggle current

    I am using a single, multi-source power supply, to which only one instruction at a time can be written.

    Where I am struggling is implementing the architecture to put this all together. If I can provide additional information, please let me know.

  20. I'm a bit out of my depth on this one, but hopefully someone out there can take a flier.

    I've taken over a system from another test engineer which entails 6 (soon to be 12) independent LV-regulated stages, on which temperature, current, and voltage are all monitored by DAQ and controlled as programmed. Temperature is controlled by the user and is monitored by polling, current and voltage are initialized by the user then controlled by the device. Also, the data collected is uploaded via SQL to a server.The program works as is, but the overall function of the current/voltage test needs to be changed to fit a change in testing protocol.

    While I make these changes, I'd like to clean up the code. The present system uses a lot of bad to awful LabVIEW protocol (the previous user had no formal training), and I'm having trouble separating the challenge of designing the architecture vs. deciphering the function/necessity of each feature.

    I'm a recent CLAD and this is a bit of a stretch for my current abilities.

    Sorry for the double post, but I realized last night that I was pretty vague in what I was after.

    I have a framework for the individual pieces (collecting/adjusting temperature, collecting/adjusting voltage), but there needs to be some interaction between the collect/adjust loops in addition to displaying the values on the front panel and writing the data to the server. Right now the method is a complicated set of local variables, and I'd like to move away from that because it's been difficult to debug. If it was one stage, I think I'd be in business, but I'm having trouble wrapping my head around how to pass and process the data for each stage in a clean way.

  21. I'm a bit out of my depth on this one, but hopefully someone out there can take a flier.

    I've taken over a system from another test engineer which entails 6 (soon to be 12) independent LV-regulated stages, on which temperature, current, and voltage are all monitored by DAQ and controlled as programmed. Temperature is controlled by the user and is monitored by polling, current and voltage are initialized by the user then controlled by the device. Also, the data collected is uploaded via SQL to a server.The program works as is, but the overall function of the current/voltage test needs to be changed to fit a change in testing protocol.

    While I make these changes, I'd like to clean up the code. The present system uses a lot of bad to awful LabVIEW protocol (the previous user had no formal training), and I'm having trouble separating the challenge of designing the architecture vs. deciphering the function/necessity of each feature.

    I'm a recent CLAD and this is a bit of a stretch for my current abilities.

×
×
  • Create New...

Important Information

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