Search the Community
Showing results for tags 'modular'.
Found 1 result
I've built (and re-built) a medium-sized application over the past months, learning more about LabVIEW in the process. The design is simplistic and reaching its limits by now, so I've been re-thinking the design lately. I'm looking for feedback on my design choices before I start implementing... all criticism and tips are welcome! The goal: flexible software for an ever-changing university laboratory environment, to be used and extended by students/staff with limited LabVIEW skills. Decisions: Avoid LVOOP unless clearly called for OOP has it's benefits but it makes code more complicated to grasp for novices. Avoid asynchronous commands unless clearly called for Many hardware operations are synchronous; these should be carried out synchronously (with time-outs) to minimize complexity. No message queues, definitely no Command architecture. Of course, queues are still OK for inter-thread communication, e.g. a data acquisition thread in a DAQ module. Modular Model-View-Controller (MVC) paradigm This should facilitate our need for extendible and adaptable software Every module needs to be able to run independently A central GUI will usually be running, but it should be possible to start/operate any module separately during run-time. This simplifies debugging and allows for flexibility during measurements ('let's quickly check the signal by hooking up a scope') Every module must be able to 'require' and 'unrequire' other modules If a measurement module is loaded, any required equipment should be initialized unless it's already running. A module should gracefully shut down when there are no modules left requiring it This is vital to prevent equipement from melting during the night! What I've come up with (core ideas are underlined): MVC implementation Each module is a lvlib containing Typedefs, Public Functions, Private functions, and Panels. The Model is a typedef'd cluster containing Settings, Data, Events, and Resources (queues, refs, etc.) The Model cluster is stored as a Data Value Reference (DVR) in a Functional Global Variable (FGV). The "First Call?" functionality within the FGV is used to initialize the Model (read Settings from a .ini file, create User Events, spawn background threads, etc.) and create the DVR. I could be re-inventing the wheel here, but I'm pretty enthusiastic about this approach. Note that the Model could alternatively be stored in a Class instance holding the DVR. This is useful in applications where you expect multiple copies of the same module (maybe you have six DAQs attached) but it complicates application design as you need to specify which instance you'd like to access before each Controller function call. The Controller is a set of synchronous functions operating on the Model. Each function obtains the Model DVR from the FGV, and uses an in-place element structure (IPES) with DVR Read/Write terminals to access and modify the data. Note that this provides some protection against race conditions, and reduces memory usage. Inside this IPES could be a second IPES, with Cluster Unbundle/Bundle terminals, to increase readability and again reduce memory usage. All Controller functions that change the Model generate appropriate User Events when doing so. Views are panels that execute public Controller functions to interact with the Model. The View registers for (a subset of) the User Events emitted by the Controller to reflect changes in the Model. Modularity Each module has public Require and Unrequire functions. These maintain a list of dependent modules, and call a (private) Stop function if the list is empty. Right now, I'm simply using the Call Chain string to identify the calling module, but there should be a more appropriate solution for this (in light of OOP, where the Call Chain is no longer unique). A View Requires its own Controller, and Unrequires it on Panel Close. A controller can Require other modules, which it must Unrequire when it no longer needs them. Hardware interfaces, software components, and measurements are all modules. Practical Example User runs the View (panel) of a Measurement Module, which starts the related Controller. The measurement controller Requires some hardware (say a DAQ board and a camera) and software (say an Error Logger) and loads certain Views (panels) to them into SubPanels (e.g. it display the Error Log). The Required modules in turn Require other modules (the camera Requires an Image Processor) or the same modules (the camera also Requires the Error Logger) which are initialized if not already running. Uses carries out his measurement, calling public functions on his required controllers. All changes are immediately reflected in the open Views through event handling. User stops his measurement and closes the view. All required modules (the DAQ, Camera, and Error Logger) are Unrequired. In turn, these models Unrequire their respective Required modules; the Camera Unrequires the Image Processor, etc. All modules shut down gracefully when there are no modules left requiring them. Concerns Unexpected errors may break the require/unrequire chain, causing modules to run indefinitely. Similarly, if a users forgets to Unrequire a module, it will live on (possibly without a panel) indefinitely. A sort of application-wide emergency stop system (using events or notifiers) could be used to 'fix' this, but I'd like to refrain from using any central structures of possible. Controller lifetime. Say two modules Require the same third module. The third module will be 'owned' by the first caller, causing it to abort when the first caller leaves memory. This leaves the second caller module with a problem. I think this can be prevented by having each controller maintain a reference to itself, which it only releases upon graceful shutdown. Will this work, and will it be reliable? Stop code in a View Panel (notably Unrequiring its controller) might not run. Again, I think this can be circumvented by having the panel maintain a reference to itself, which is only released after calling graceful shutdown code in the Panel Close event case. Wow, that sure turned into a short novel. If you're still with me, I'd love to hear your thoughts!