From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Integrating AF & LVOOP with hardware

Solved!
Go to solution

@cbutcher wrote:

@WavePacket wrote:

I'm not exactly sure what you mean by adapters/adapters. Do you mean that the test stations have the burden of writing the code to supply the required inputs to the database interface?


Hmm, I'd be willing to put it on either end (you could write the code separately from the test stations, but separately from the "database interface/system"), but essentially, yes.

 

For me, the database code should handle the database, not the test systems. If the interface you want for your database is convenient for the test systems (you might choose an interface that has "Store Result.vi", "Get Configuration Parameters.vi" taking a Test Station identifier, etc) then that's great. There's no inherent reason this shouldn't be the case.

 

However, if the database interface is more "generic", for want of a better term, then I don't think that's necessarily a problem either. I understand a desire not to make Test System Actors/libraries closely coupled to the database (i.e. containing SQL statements, table names, whatever), but if you don't want either one to match the other, write some separate code to bridge the gap.


Ok, thanks.

 

So I'll take another stab and rephrasing (mostly just to see if I understand), and adding a bit -- this solution is essentially too make the interface as reusable as possible but when specific needs arise it does mean somewhere someone has to write specific code. The best place for those specifics is the specific test software that needed them. To add a bit, I suppose this is comparable to my #4 above. The database actor gives you access to the data via generic interfaces and if you have a very specific need I was previously considering writing a specific SQL query. Let's maybe not do that but instead of a specific SQL query to do the logic, let's rather just give you the data via the generic interface and then you can write LabVIEW code to do the equivalent logic of those SQL queries.


------------------------------------------------------------------------------------

Please join the conversation to keep LabVIEW relevant for future engineers. Price hikes plus SaaS model has many current engineers seriously concerned...

Read the Conversation Here, LabVIEW-subscription-model-for-2022
0 Kudos
Message 41 of 88
(1,709 Views)

@WavePacket,

 

Having just read that more messages were posted while typing this, I am likely repeating what cbutcher wrote. You may need to consider abstraction at the highest levels of your problem domain (your test stations?), and set up actors at those levels. This way, the interfaces implemented will all be meaningful for each domain.

 

Your problem-domain specific actors each will be composed of an abstract class (as Sam Taggart initially recommended). Each abstract class (i.e. adapter) will expose only the application-specific APIs for your corresponding hardware class, again via composition. The hardware class (not an actor) will still be full-featured, reusable across problem-domains.

 

Regarding database, it is, to me, another concrete entity whose implementation is to be abstracted out (yes, that word again) based on your problem domain. You may be referring to the same database for multiple purposes (system configuration, user management, test results), it doesn't matter - you would still need to abstract those purposes out at the problem-domain level. In other words, separate abstract classes for each intention - load/save configuration or manage users or log test results.

0 Kudos
Message 42 of 88
(1,709 Views)

@WavePacket wrote:

@drjdpowell wrote:

Why do you have a "database actor"?  Databases are a lot more sophisticated than some dumb hardware.  They support multiple clients with transactions and ACID compliance.  Why not use them directly?


"Why" is that there are a few times where I want the asynchronous behavior. For example, there is a software where I want to populate query results as they come. The user is likely interested in the latest results but could infrequently be interested in old data. So I want to present the newest results first, but asynchronously continue to fill in old results as they come back. The query is long enough that I don't want to make the user wait for all results to come back.

 

Another possibility is that as a test proceeds, I want to asynchronously be asking the database as we go along if the test results are normal (but allow the test to continue until the database responds with a warning). Kind of like an asynch background check of the results.

 


Databases are already asynchronous.  More capably asynchronous that you Actor is.  Databases can generally support multiple Readers and Writers at the same time, and have a Transaction system to keep things straight.  Your Database Actor is not able to do these things, and by putting a single Actor as gate-keeper to the Database you are significantly reducing the asynchronous capability of your App, or at least you are forced to reinvent the wheel.

0 Kudos
Message 43 of 88
(1,700 Views)

@drjdpowell wrote:

@WavePacket wrote:

@drjdpowell wrote:

Why do you have a "database actor"?  Databases are a lot more sophisticated than some dumb hardware.  They support multiple clients with transactions and ACID compliance.  Why not use them directly?


"Why" is that there are a few times where I want the asynchronous behavior. For example, there is a software where I want to populate query results as they come. The user is likely interested in the latest results but could infrequently be interested in old data. So I want to present the newest results first, but asynchronously continue to fill in old results as they come back. The query is long enough that I don't want to make the user wait for all results to come back.

 

Another possibility is that as a test proceeds, I want to asynchronously be asking the database as we go along if the test results are normal (but allow the test to continue until the database responds with a warning). Kind of like an asynch background check of the results.

 


Databases are already asynchronous.  More capably asynchronous that you Actor is.  Databases can generally support multiple Readers and Writers at the same time, and have a Transaction system to keep things straight.  Your Database Actor is not able to do these things, and by putting a single Actor as gate-keeper to the Database you are significantly reducing the asynchronous capability of your App, or at least you are forced to reinvent the wheel.


I'm familiar with concurrency in databases. What I need though is asynchronous behavior in my app, but from the databases perspctive it might not need to the asynchronous connections. If I desired asynchronous behavior in my app, and asynchronous database connections would your suggestion be something like launch many copies of async VIs to launch more than one query simultaneously?


------------------------------------------------------------------------------------

Please join the conversation to keep LabVIEW relevant for future engineers. Price hikes plus SaaS model has many current engineers seriously concerned...

Read the Conversation Here, LabVIEW-subscription-model-for-2022
0 Kudos
Message 44 of 88
(1,696 Views)

@Dhakkan wrote:

@WavePacket,

 

...

 

Your problem-domain specific actors each will be composed of an abstract class (as Sam Taggart initially recommended). Each abstract class (i.e. adapter) will expose only the application-specific APIs for your corresponding hardware class, again via composition. The hardware class (not an actor) will still be full-featured, reusable across problem-domains.

 

...


I'm trying to understand your reply. Using the specific example (link) mentioned before, let's assume that I have a test measuring just current, but it uses a physical multimeter that can measure more than just current. In LabVIEW the multimeter is a class, and the class inherits from an interface corresponding to each measurement the device is physically capable. Is your suggestion:

  • have a test software actor, that test software actor via composition owns of an abstract class
  • that abstract class would be composed of just the current interface

 

First, do I understand your suggestion right? If I am, what does this get me over just having a test software actor composed of the current interface? That I'm asking that second question likely reveals I'm rather green at the concept of "adapters".


------------------------------------------------------------------------------------

Please join the conversation to keep LabVIEW relevant for future engineers. Price hikes plus SaaS model has many current engineers seriously concerned...

Read the Conversation Here, LabVIEW-subscription-model-for-2022
0 Kudos
Message 45 of 88
(1,680 Views)

@WavePacket wrote:

I'm trying to understand your reply. Using the specific example (link) mentioned before, let's assume that I have a test measuring just current, but it uses a physical multimeter that can measure more than just current. In LabVIEW the multimeter is a class, and the class inherits from an interface corresponding to each measurement the device is physically capable. Is your suggestion:

  • have a test software actor, that test software actor via composition owns of an abstract class
  • that abstract class would be composed of just the current interface

 

First, do I understand your suggestion right? If I am, what does this get me over just having a test software actor composed of the current interface? That I'm asking that second question likely reveals I'm rather green at the concept of "adapters".


In the case of the test where your need is only a current measurement from a multimeter, you may not even need an actor. To illustrate where an actor may be warranted for the same interfaces and devices, consider this hypothetical scenario: Your application needs a watchdog to ensure connectivity of your target device. One way of doing that is by continuously measuring current flow through a particular point. If measured current exceeds a threshold, then the target is deemed connected. The class diagram below may give a clearer picture.

 

Dhakkan_0-1634765958792.png

 

Here, ConnectionWatchdog class is the only actor, which will be used as a nested actor. Connection can be checked at configurable intervals. If connection is established, targetIsConnected message is sent. If connection is lost, targetIsDisconnected message is sent. It encompasses a WatchdogDevice, whose only requirement is current measurement from any device with that capability. The decision to use a Multimeter or not, is up to one's implementation needs. The key takeaways I wish to point here are

  • The caller actor launches and activates ConnectionWatchdog actor without explicit knowledge that the latter is using a multimeter internally.
  • The caller actor implements ConnectionWatchdogAnnouncements, which is completely problem-domain specific, even though they may be implemented through current measurements.
  • The devices themselves do not need to be made into actors just to provide their measurements.
  • Well-defined actors have a clear raison d'etre within the problem-domain.

 

I have successfully used a similar concept in a track-and-trace application; where freshly printed barcodes on production units need to be verified in-situ. From a problem-domain perspective, my requirement was to visually verify an array of expected barcodes. Here, the actor is (amateurishly) called ScannerActor. Upon being asked to verify a list in each call, it produces either of two 'announcements'. allBarcodesVerified() OR barcodesMismatched(with a list of mismatched barcodes). Upon receiving the first announcement, the caller actor's override is implemented to route all production units to a 'shipping' bin. With the receipt of the second announcement, the caller actor override routes the rejected production units to a 'rejects' bin; and puts the remaining into 'shipping'. The actor itself calls an abstract scanner class to allow for simulation testing with a simulated device driver or live production with a real scanner device driver.

 

Hope this provides better clarity.

0 Kudos
Message 46 of 88
(1,671 Views)

Nice example Dhakkan. I'm not the person you were talking to, but if you don't mind, could you elaborate on this part:


@Dhakkan wrote:

  • The caller actor launches and activates ConnectionWatchdog actor without explicit knowledge that the latter is using a multimeter internally.

I get that the caller actor shouldn't know about the multimeter, but I find this "breaks down" a bit when configuration comes into play. For example, if I was to configure the main program, at some point I have to say "OK you are using a multimeter on COM4" or whatever. I usually have my config editor in my main actor, so it winds up knowing about all kinds of parameters.

 

Theoretically I can imagine ways for you to dynamically load your potential configurable actors with each one providing a Config screen which can be dynamically loaded into a subpanel. Then your main actor wouldn't need to know ANYTHING about your called actors, but I'm not sure how I'd implement this in practice in a nice reusable way.

0 Kudos
Message 47 of 88
(1,663 Views)

 


@BertMcMahan wrote:

Nice example Dhakkan. I'm not the person you were talking to, but if you don't mind, could you elaborate on this part:


@Dhakkan wrote:

  • The caller actor launches and activates ConnectionWatchdog actor without explicit knowledge that the latter is using a multimeter internally.

I get that the caller actor shouldn't know about the multimeter, but I find this "breaks down" a bit when configuration comes into play. For example, if I was to configure the main program, at some point I have to say "OK you are using a multimeter on COM4" or whatever. I usually have my config editor in my main actor, so it winds up knowing about all kinds of parameters.

 

Theoretically I can imagine ways for you to dynamically load your potential configurable actors with each one providing a Config screen which can be dynamically loaded into a subpanel. Then your main actor wouldn't need to know ANYTHING about your called actors, but I'm not sure how I'd implement this in practice in a nice reusable way.


Disclaimer: I do not use NI Actor Framework (aka AF), but this is a much broader discussion, so I would chime in. I've presented this on multiple occasions over the years and the solution I practice repeatedly is Dependency Inversion Design Principle (the D in SOLID) and Dependency Injection Design Pattern. A slide from a more recent presentation:

 

Dmitry_0-1634783824520.png

 

And Presenter Notes:

 

"Dependency Inversion Principle (Part A) requires classes to be statically decoupled from their subsystems through well defined and stable interfaces. Which creates a problem – who should be responsible for creating & configuring subsystem objects? Creating an object requires knowing a concrete class of the object – statically coupling subsystem creator to ‘the details’ …

 

Enters Dependency Injection Design Pattern (note – it is not one of the Agile Principles). Using Dependency Injection is about making a conscious decision to separate Reusable Code from Application Specific Details.

 

A Dependency Injection Container (AKA Assembler class) is, simply put, an object that knows how to instantiate and configure all other application objects and all their dependencies. “Injection” is just a big word for passing something as an argument to an object method call. The two widely used Dependency Injection flavors are Constructor Injection (passing something to a class constructor) and Setter Injection (passing something via class accessor methods)

 

  1. Assembler Class groups all application-specific details (knows everything about the app) – making it easier to bring-up and tear-down the application
  2. Assembler Class configures application-wide subsystems : Configuration Management, Logging, Error Handling, Messaging Support
  3. Assembler Class instantiates and configures Reusable Class Instances (objects)
  4. Assembler Class injects Dependencies (objects) into Higher-Level Objects

Using Dependency Injection is a choice that has the most visible effect on your application structure …"

 

 

Message 48 of 88
(1,660 Views)

@BertMcMahan, Pleased to make your acquaintance virtually.

@BertMcMahan wrote:

I get that the caller actor shouldn't know about the multimeter, but I find this "breaks down" a bit when configuration comes into play. For example, if I was to configure the main program, at some point I have to say "OK you are using a multimeter on COM4" or whatever. I usually have my config editor in my main actor, so it winds up knowing about all kinds of parameters.

 

Theoretically I can imagine ways for you to dynamically load your potential configurable actors with each one providing a Config screen which can be dynamically loaded into a subpanel. Then your main actor wouldn't need to know ANYTHING about your called actors, but I'm not sure how I'd implement this in practice in a nice reusable way.


That has been one of my struggles as well.

 

Of late, I have been using a deliberately simple implementation that works for my co-workers and me. The attached library can be opened with LV2020 or later. As you will see, it is biased to use the Windows INI format to determine the class to instantiate. The library also implicitly assumes that all configurable classes follow a specific naming convention: <Name>.lvlib:<Name>.lvclass. The required VIs are set to be recursively called, when instantiating nested compositions.

 

We sidestep class-loading from file (Get LV Class Default Value) by plonking all required class constants into the root launcher VI, and instead use 'Get LV Class Default Value By Name'. This has helped us to avoid, for now, the learning curve associated with packaging the classes and actors for executables.

 


@Dmitry wrote:

Disclaimer: I do not use NI Actor Framework (aka AF), but this is a much broader discussion, so I would chime in. I've presented this on multiple occasions over the years and the solution I practice repeatedly is Dependency Inversion Design Principle (the D in SOLID) and Dependency Injection Design Pattern. A slide from a more recent presentation:

 

Dmitry_0-1634783824520.png

 

And Presenter Notes:

 

"Dependency Inversion Principle (Part A) requires classes to be statically decoupled from their subsystems through well defined and stable interfaces. Which creates a problem – who should be responsible for creating & configuring subsystem objects? Creating an object requires knowing a concrete class of the object – statically coupling subsystem creator to ‘the details’ …

 

Enters Dependency Injection Design Pattern (note – it is not one of the Agile Principles). Using Dependency Injection is about making a conscious decision to separate Reusable Code from Application Specific Details.

 

A Dependency Injection Container (AKA Assembler class) is, simply put, an object that knows how to instantiate and configure all other application objects and all their dependencies. “Injection” is just a big word for passing something as an argument to an object method call. The two widely used Dependency Injection flavors are Constructor Injection (passing something to a class constructor) and Setter Injection (passing something via class accessor methods)

 

  1. Assembler Class groups all application-specific details (knows everything about the app) – making it easier to bring-up and tear-down the application
  2. Assembler Class configures application-wide subsystems : Configuration Management, Logging, Error Handling, Messaging Support
  3. Assembler Class instantiates and configures Reusable Class Instances (objects)
  4. Assembler Class injects Dependencies (objects) into Higher-Level Objects

Using Dependency Injection is a choice that has the most visible effect on your application structure …"


Thanks! for the very elegant post. I hope to be able to completely 'program to interfaces' some day. 🙂

 

0 Kudos
Message 49 of 88
(1,645 Views)

@WavePacket wrote:

@drjdpowell wrote:

@WavePacket wrote:

@drjdpowell wrote:

Why do you have a "database actor"?  Databases are a lot more sophisticated than some dumb hardware.  They support multiple clients with transactions and ACID compliance.  Why not use them directly?


"Why" is that there are a few times where I want the asynchronous behavior. For example, there is a software where I want to populate query results as they come. The user is likely interested in the latest results but could infrequently be interested in old data. So I want to present the newest results first, but asynchronously continue to fill in old results as they come back. The query is long enough that I don't want to make the user wait for all results to come back.

 

Another possibility is that as a test proceeds, I want to asynchronously be asking the database as we go along if the test results are normal (but allow the test to continue until the database responds with a warning). Kind of like an asynch background check of the results.

 


Databases are already asynchronous.  More capably asynchronous that you Actor is.  Databases can generally support multiple Readers and Writers at the same time, and have a Transaction system to keep things straight.  Your Database Actor is not able to do these things, and by putting a single Actor as gate-keeper to the Database you are significantly reducing the asynchronous capability of your App, or at least you are forced to reinvent the wheel.


I'm familiar with concurrency in databases. What I need though is asynchronous behavior in my app, but from the databases perspctive it might not need to the asynchronous connections. If I desired asynchronous behavior in my app, and asynchronous database connections would your suggestion be something like launch many copies of async VIs to launch more than one query simultaneously?


As an example, let's say we have:

Actors A, B, and C that collect data and save to the database.

Actor D that analyses the recent data and saves results in the database.

Actor E that watches the database to display if results seem normal.

Actor F that displays recent results from the db.

Actor F that displays long-term trends in the db.

 

All these Actors can independently talk to the database.  So what is your "Database Actor" for?  What does "I need asynchronous behavior in my app" even mean in this context, given that all these Actors have clear and simple single-purpose roles?  Actor F, for example, may have to wait a bit for it's long-term trends Query, but it doesn't have anything else to do while it is waiting, so why would it need an asynchronous db query?

0 Kudos
Message 50 of 88
(1,619 Views)