Jump to content

drjdpowell

Members
  • Posts

    1,969
  • Joined

  • Last visited

  • Days Won

    172

Posts posted by drjdpowell

  1. I use warnings to tell users/developers that data is being dropped and an error is not appropriate for that.as it is a designed feature to protect the server/client.

     

    The speaker who called it an anti-pattern was Dmitry, at the recent CLA Summit in Berlin.  I don’t think he posts on LAVA, but I suspect he might argue that calling code should decide if “data being dropped†is acceptable or not and thus either dropped data should be an error (with calling code forced to decide what to do) or it should be a separate output, such as a “data dropped†boolean, which calling code should immediately either handle or explicitly choose to ignore.  

  2. Thanks Neil,

    The toolkit gives off a “not quite ready for prime time†vibe to me (including that annoying partial implementation of events, poor documentation, minimal single example, etc.) so I’m glad you are happy with it.  I suspect it is an incomplete version of OPC-UA (no method calls?) but probably sufficient for the simple server I need to make.

     

    Thanks again,

    — James

  3. HI Rob,

     

    Have you looked at the example code (and video linked to) here?  It’s a TCP example.   Standard Request-Reply and Register-Notify should work seamlessly over TCP (as the various TCP actors route the messages back over the connection) without needing to do anything special.

    • Like 1
  4. Also opening another can of worms...do you often have parent-child inheritance situations where an actor inherits from another?  For instance, for an "instrument" do you have an abstract parent and implementation in a child actor or do you make the messages abstract (message names shared between the same instrument type) such as "measure" and "set range" and the actors of the same instrument type do not inherit?

     

    I use composition instead of inheritance: actors with common behavior will all use some common class to get this behavior.  You can change the “Default†message case from throwing an error to calling a “Handle Message†method of some common class.  The “Pipeline Component†actor classes, in the example above, all contain a common class that handles common messages (the actors can “override†these messages by choosing to explicitly handle them).  Note that you can inherit off of this common class and inject different behavior to your actors by having the caller send the common class to the launched actors.

     

    Below is an example that is as close as I’ve done to all-internal-data-in-one-object.  All this actor does is receive a “Graph Augmentation†object from it’s caller, then it passes all events on a graph to methods of this object.  It also passes any unknown message to the “Receive Msg†method.     “Graph Augmentation†is a parent class of several children that actually do things, and 99% of the work is done in methods of this class.   This is quite powerful, but it is also harder to figure out what is going on.  You would have an easier time understanding my other example, because you can see high-level stuff happening on the diagram.  Here it is just “Cursor Moved—> call 'Cursor Moved’ dynamic-dispatch method; Message Received—> call 'Receive Message’ DD methodâ€.

     

    post-18176-0-91117600-1459541641.png

  5. Is it OK to put an Actor's "Internal Data" into its class control? or does it need to be empty?  I ran out of space on the actor diagram and had to make SubVIs to parse some messages and handle some follow on actions.   The internal data is a relatively big cluster and takes up a lot of space on the front panel of the SubVIs and could be cleaned up if it was a class wire.  Do you try to keep everything on the top level block diagram as good practice? 

    Personally, I tend to look to see if some of the actor’s data should really include one or more classes, then my subVIs are methods of these classes.  I generally try not to have a class that is all the data of the actor, or have subVIs that pass in all the data (you’ll note I don’t even type-def the Internal-Data cluster).  I like the high-level actions to be on the top-level block diagram, but the details hidden in more specific subVIs that only act on part of the date.  For example, here is a Top-level actor that presents a picture to the User, showing a “pipeline†of analysis actors, where the User may modify the pipeline by adding, deleting, copying and pasting.  The code for copy/delete is shown.

     

    post-18176-0-69634000-1459539141.png

     

    post-18176-0-00664300-1459539161.png

     

    This code is basically: If the User selects “Deleteâ€, then identify which icon was clicked on, write the deleted actor to the Clipboard (so the User has the option of pasting it elsewhere in the pipeline), and delete it from the Pipeline list of actors (calling "change pipeline.vi†to complete this).

     

    There are three complicated bits of detail here, but they each only need part of the Internal data.  There is a method of the “Icon Picture†object that handles all the details of the picture (rather complex internally); a method of the (not so complicated) “Clipboard†object; and a subVI that acts on arrays of “Pipeline Component†Actors.  No subVI needs all actor data.   

     

    BTW, the actor class here (your “Solo_Msg.ctlâ€) is actually serving as the address of the actor to external processes, so I wouldn’t try and make it do double duty as an internal-data store.  Instead, you could make a different class.  You could even have the actor’s caller preconfigure such an object and send it to the actor after launch.

  6. Using a number of interaction queued message handlers (QMH) is quite a common architecture (sometimes known as “actor-oriented design").  There are multiple packages in the community that people have made available**, and I believe quite a few people have their own private implementations.   Personally, I usually have a separate QMH for each independent bit of hardware.   I have sometimes done an LVOOP driver (with child types) inside a QMH, which I think is what you are describing.

     

     

    ** Mine is Messenger Library (an introductory video); there is also the Actor Framework (part of LabVIEW), Delacor DQMH, and Aloha, just to name a few that are available on the LabVIEW Tools Network, and you’ll find a few other examples on LAVA such as Message Pump.

  7. Do you have specifications for the different types of units?  If so, you can query the unit for its type then load something specific to this type.   Could be a special INI file for each type, or a child class if you are using LVOOP.  The file/class would specify what settings are available.

     

    Are you testing these units, or just using them?   With testing you should test to the spec, not query the unit for what it can do.  Otherwise you won’t catch a unit that fails to support a setting that it actually should.

  8. Hi,

     

    I am doing a project using your messenger library as it seems very interesting and easy to use.

    However, I do have a question about the reentrant actors.

    I want to be able to launch multiple instances of the same actor, and afterwards choose to which one of the instances I want to send a message.

    I tried to put the actors in an array after launching but that doesn't seem to work.

    Is there a way to do this?

    Is your actor reentrant?  The VI should be named “Actor.vi†(rather than ActorNR.vi) and set as shared-reentrant.  If that isn’t the problem please post an image of your launch code.  I use arrays of actors in some of my projects (and the library has VIs meant specifically to work with arrays) so it does work.

  9. On March 13, 2016 at 1:48 AM, jimc1041 said:

    Your instructional videos on the Actor to Actor communication are very informative. However, I had trouble when I tried to modify the examples to utilize your TCP messengers such as would be required for a remote cDAQ/cRIO system. Do you have any examples of this nature?

    See this new video on youtube.  I modified the demo so that 'Instrument' is running on a separate project behind a TCP server, with 'Top Level' connecting as a client via a Remote TCP Messenger.  I also showed the use of an 'Address Watchdog' to shutdown 'Top Level' if ‘Instrument' disconnects.  

     

    Here is the code (start the server first):

    Messenger TCP Server.zip

    Messenger TCP Client.zip

     

    I think I forgot to mention it in the video, but note that the Client project does not load the code of “Instrument", and the Server Project does not load the "Top Level" code.  Thus, nothing is locked and you can edit freely (this is a problem in some architectures).  This is done internally by the TCP server/client actors by keeping all reply addresses in flattened form on the remote target.  If you use custom probes you will see most replies or registrations become something like "Route back to QueueMessenger and then to Flat", which is confusing but means "send back to the TCP actor running this connection, then via TCP to the remote system, and then to this address (unflattening it first)".  Please note that only Reply Addresses are converted; you cannot send an address as data in a message and have it work on the remote system (attach it as a Reply Address instead).

     

    Please note that I have yet to do a Real-Time project with Messenger Library.  I do have a current project using modified TCP actors to communicate with a non-LabVIEW client from another developer (using JSON messages), but that isn't the same.  So please don’t be afraid to ask for help or to make suggestions.  Please see if you can run this example with ‘Instrument' on the Real Time system.

     

    -- James

     

     

    TCP example Actor Manager.png

    Actor Manager for this TCP example.  Note that the 'Control Server' actors are entirely unmodified, and have no knowledge that they are talking to 'Instrument' via TCP.   Because everything is by message (no DVRs, no Action Engines) it is easy to convert things to remote operation.

    • Like 1
  10. I’ve added a couple of more videos about the Register-Notify system used in Messenger Library.   A couple of people identified Notifications as something I had not explained sufficiently (especially the difference between an “event†and a “state†notification).  So I have added Register Notify and Notification “Hookup†of a dynamic actor (and generic messages).  The later video also shows a technique of handling messages to do with multiple controls in a single Variant-based case.

     

    Updated example code:Messenger Library Demo.zip

     

     

    I’ve also made an initial Introductory video to SQLite in LabVIEW.

  11. Is it worth making the scalar parser more robust?

    Possibly.  If one was sending a stream of JSON (including some scalar strings) then this would cause a failure.  However, if some of those scalars were number, like 123.456, then there would be no way to be sure you had the full value as 12 or 123.4, etc. are valid JSON.  So to guard against partial JSON one might have to require streams to use either an Object or Array.

  12. BLOBs are just a binary data type, same as TEXT but without the need to treat binary data for special characters.  Use “Bind BLOB†when your LabVIEW string isn’t actually text.  

     

    Have you considered just saving each waveform in a separate file, and storing the filename in SQLite?  Then overwriting is easy.  

  13. Hi James,

     

    Thanks a lot for this library. This is wonderful.

     

    I am using sqlite to store the measurement data. My data is 1D DBL and each waveform is about 5s @ 48k sampling rate so that makes the size of each waveform to be ~2MB. I flatten the data to string and replace any special chars(like NULL and ') and save the data as TEXT. All that is fine but if I want to retrieve say 10 waveforms, it takes about 350-400 ms to return the data which is not acceptable as the code will be used on a production line and time is a very critical factor over there. Also if I use action engines to store the waveforms then retrieving 10 waveforms only takes about 20ms on the same machine. I don't want to use action engines because the amount of data to store is going to be huge and thats why I am inclined to use sqlite.

     

    Is it normal for sqlite to take about 400ms to retrieve 20MB of data? 

     

    Thanks,

    Ritesh

     

     

    I’m not sure SQLite is the best choice here.   Large waveforms is something TDMS is built for.  SQLite is better for structured data where one wants powerful filtering ability to pull out only the small subset of information one needs.  TDMS already has useful features like the ability to store scaled U16 values rather than 8-byte DBL (I’ve done this is SQLite, but it more work).  You could mix the two approaches, storing metadata about your waveforms in SQLite, along with a filename and waveform name pointing to the TDMS file with the waveforms itself.

     

    BTW, if you store your flattened waveforms as BLOB, then you don’t need to replace any special characters.  But, as I said, once one is doing this one has lost to big benefit of SQLite, the ability to query your data, so I think you should consider TDMS.

  14. @drjdpowell: I installed the latest version of your library (1.6.2). There is a new VI called "SQLite Database Path" which is missing the output terminal for "Last INSERT RowID":

    attachicon.gifSQLite Database Path missing terminal.png

     

    Oh dear, that was amateurish. This is an unfinished VI that I obviously never tested.   Sorry about that.  I’ve only been using WITHOUT ROWID tables recently, and in the past I’ve only generated the rowID in LabVIEW and thus never used this dll call.  

     

    Added later> fixed 1.6.3 version now in the LAVA-CR (note, LAVA will often have a later version than on the LabVIEW Tools Network)

    • Like 1
  15. Hi, very nice library here. I am very impressed with it and sqlite. 

     

    I was wondering would this library work on labview linux RT? 

     

    I don’t have a system to test, but the library attempts to find the copy of libsqlite.so if it is installer on the Linux RT system (see the series of posts starting here).  Stobber can give you better information, as he was trying to do this.  

×
×
  • Create New...

Important Information

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