Jump to content

dhakkan

Members
  • Posts

    14
  • Joined

  • Last visited

Everything posted by dhakkan

  1. I misread and misinterpreted your usage of the 'UpdateStatus' message in the Writer - I thought that you were looking to 'write' the status value of the Reader's UpdateStatus into the TDMS file using the Writer's UpdateStatus message. Looking at the pictures above; the code samples, and re-reading your OP, it's clear now that you want both nested actors to apprise the caller of their respective status. My comment is totally invalid. Regarding your primary issue though, You could break up UpdateState.vi into the names you already indicated. E.g. Acquiring.vi; Writing.vi, etc. This way, the messages will not have any additional inputs in the connector pane; and the Controller will know exactly what to do when it receives a specific status message, without the need for case-structuring. (With UpdateState, I assume that you would need to case out your next action in the Controller based on the input state value.) From a reusability perspective, one could end up with a similar, if not same, problem if multiple nested actors of the same class are sending their status to the Caller. E.g. If using multiple Writer actors to write to TDMS files concurrently, how would the Controller know which nested Writer is reporting its status; unless the status message includes some form of identification of the nested actor (say nested-actor's enqueuer). I encountered a variant of the problem you posed, whereby I made various instrument actors (PowerSupply, Chiller, VacuumController, etc.) implement a Connectable interface with messages for connect and disconnect. That was easy. But, when I wanted to convey their status - connected and disconnected - to the caller, I was stuck. I ended up following a bit of advice from another post (can't find it now). The gist (as I understood it): the caller 'trusts' that the nested actor has performed the requested action. If the nested actor has not, it will send a well-defined error report. Exception handling is then done according to the problem domain. As a result, I didn't use 'connected' and 'disconnected' type state messages any more.
  2. Per my understanding, having two separate names is required. Changing the name of the VI publishing the data to the caller ("reader" in your case) to an announcement that the action has been completed, will likely make your communication semantically meaningful. E.g. Reader's announcement via the interface could be "dataPacketAcquired" or equivalent. When Controller implements this method, it will request the Writer to 'updateStatus', as you currently have. In general, a mantra I've been following is: Nested1 -> eventOccurred -> Caller -> doSomething -> Nested2. Edit (an hour later): Also., from a design perspective, your Controller should NOT be implementing (inheriting) the updateStatus capability - that rests with the Writer.
  3. Never had the need to implement it; so I can't speak to the difficulty of implementation in LabVIEW. The Memento Pattern may fit your needs.
  4. Hello. I haven't gone through the links provided in the opening post. However, it appears that Darren's recommendations pertain to the concept of (class or object) immutability - the general idea being that, once an object is created, its identity must be unique in your application domain. Note, however, this does not mean all class data members are constant - just the crucial attributes that 'define' the object. For example, a human being continuously evolves since inception. However, certain traits remain immutable, depending on the domain of reference: Biologically - DNA; Government - government issued ID#, etc. In my case, I am happy saving certain class data members without references, because I know those don't get overwritten once the object is created. E.g. 'id' as string - gets assigned when object is instantiated. All others are saved via references. My general heartburn vis-a-vis references, is the worry of how to group the data members for referencing. One DVR for all class members, though easy to implement, has greater chance of causing deadlocks. Although those ought to be caught with adequate unit testing. Of course, making all data members references ensures a consistency in implementation; as opposed to a mix of by-ref and by-val data members. The Actor Framework is neat in this context - when a launch actor is invoked, the output is actually a reference to the actor's unique 'mailbox'. Therefore, regardless of the number of wiring branches one invokes on that output; all 'messages' go back to the launched actor. IMHO, there is no need to save class member data as references in such frameworks, as long as the actor's internal logic is implemented without risk of race conditions.
  5. Assuming these log files are to be consumed for application support, here are a couple of more possibilities for viewing logs saved in chronological order. Use 'tac' (reverse of cat) from the terminal. This differs from 'tail' command in that tac presents lines in the reverse order, whereas tail presents lines in the same order as saved in the file, but from an offset relative to the End-Of-File marker. tac is built-in for linux terminals. I don't know of Windows command or powershell built-in equivalents - I couldn't find anything from a cursory search. GNU utilities can be downloaded for Windows for the same tac tool. If you use Notepad++ (Windows only), this link has a built-in approach requiring a few steps. EDIT 1: Reg. 'large' log files, log rotation may help. Linux has 'logrotate' available. For Windows, I just implemented a rudimentary function in LabVIEW. File size is checked periodically. When a predefined threshold size is exceeded, the existing file is flushed, closed and moved to an incrementally numbered file based on already existing numbered files in the same folder.
  6. At the outset, my apologies for the delay in acknowledging your responses - a holiday trip and getting under the weather did not help... Thanks! that helps. A clever way to get the separator, though! Am confused by 'Command Line String To Path.vi'. Under the wrapper it seems to call the native 'String to Path' function except for a Mac OS 32-bit application. In this exception case, not-a-path constant is returned. That doesn't seem to help solve my problem. Now, I'm using the solution candidus provided to build the necessary relative path. Thanks! folks, for your help; and a very Happy New Year to one and all.
  7. Happy New Year to you too! I did a quick check on my machine. Was able to reproduce the problem running LV2015 32-bit on Win10x64. I created a folder called ABCD in 'C:\WIndows\System32'. A Google search led to the following link in MSDN. Do read the embedded link within the first response about file system redirector. That throws more light. I created another folder ABCD, this time within 'C:\Windows\SysWOW64'; and created an empty file there. Re-running my LV sample, which is still coded for 'C:\Windows\System32\ABCD' is now successful; and the empty file does get listed with the List Folder function call! Bottomline: 32-bit apps on Win64 will be redirected to 'C:\Windows\SysWOW64'. Hope this helps. Cheers!
  8. Hello, I'm experimenting with porting my existing LabVIEW application from Windows to Mac OS X. The code uses several instances of 'Build Path' function in 'File I/O' functions sub-palette. The 'Name or Relative Path' input is being connected with a 'string' data type rather than a 'file path' data type. With some quick code change and checks, I've realized that it's better to use the latter data type, so that the separator character '\' in Windows is automatically interpreted as ':' in Mac OS. Some parts of the code, however, build up the string. E.g. a 'Format Into String' is used to output based on a format string, e.g. 'Images\%s.jpg'. Doing a 'String to Path' after this function does not automatically interpret the '\' in Mac OS to ':'. (I can imagine that it would be difficult for the compiler to recognize that a specific character is meant to be a separator and not part of a file/folder name.) I can write more complicated code where the format string is itself concatenated based on the execution platform. Are there any easier or recommended approaches? Also, does LabVIEW have any 'File Constant' that provides the equivalent string character depending on the platform? Thank you.
  9. Hello, First off, kudos on the effort! I did a quick read-up. Overall, a great write-up! Parts 3, 4 and the walkthrough were the most helpful for me (as one who has been struggling to appreciate this implementation of AF). The introduction in Part 1 was also great; however, I got confused by the last paragraph. Will read it again with a clearer head. Cheers,
  10. Sorry about reviving an old thread. However, am hoping this may help... My 2c follows. Consider using LabVIEW's bookmarks and subdiagram labels. I'm beginning to use the former as follows: #TBD for any part of code that needs to be re-visited for any reason. Goal is, by the end of development cycle, no such bookmarks must remain. #<NameOfDev> for any part of code that needs to be re-visited by the named Developer. Goal is, by the end of development cycle, no such bookmarks must remain. #Rationale for any part of code that needs an explanation of why the implementation is so. (This would include info about trying other approaches as stated in earlier posts.) #Info for any part of code that needs an explanation of what it does. This is particularly necessary when Uncommon algorithms are used Complex regular expressions are used. Making specific assumptions not clear from code. #Reference for any part of code based on reference material available to the developers. Rationale: The first two bookmarks above are meant to be on-the-spot reminders for developers to verify or seek additional information when having questions. The remaining bookmarks are meant to aid future developers for easier code maintenance or revisions. The Bookmarks Manager helps with finding the first two prior to release, provided Developers are diligent and consistent enough... Subdiagram labels help me a fair bit. I use them initially to jot the implementation approach; then refactor the verbiage as needed following the hashtags above. Reg. context help... For low-level VIs, if the inputs, VI name and outputs are not not self-explanatory; there is likely scope for improvement in the names. That said, of late, I've started to document non-default VI execution properties in the context help. (E.g. 'Shared reentrant', execution thread, etc.). It would be great if NI would make context help more powerful by displaying these important non-default properties. Lots of people seem to support this in the idea exchange... I've also started to specify a line in context help if VI does NOT provide 'standard error out' functionality. I don't provide separate 'detailed help' documentation unless contractually bound to do so. For higher-level VIs, a paragraph-size explanation of the 'process' (considering the input->process->output paradigm) would should be sufficient. If more information is warranted than the above two points, then it's better to provide 'detailed help' for those VIs. I used to label wires a LOT. Have toned it down as follows. Attach a label to a 'shift register' outside the sub-diagram, if its initial value is not immediately apparent (e.g. a case that's not displayed). Apply a label with direction in case a wire originates at a point beyond the visible part of the block diagram. E.g. 'PSU Object ->'. If a feedback node is used the direction could be right-to-left, in which case '<- PSU Object' would work. Don't label a wire otherwise. It's easy enough for the Developer to open the context diagram and see its source or sink to determine what it is. I label a constant primarily if it is not obvious from nearby labels. Another example of the obvious: Type-def constant should not need labeling given that its info is visible in the context help.)
  11. Gotcha. Thanks for the tips too! (I'm pretty new to posting on discussion forums in general, let alone LAVA.)
  12. Hello Rolf, Not sure where I implied that... Sorry, if the write-up was not clear. I was of a different opinion when I started writing that post as compared to when I finished it a few minutes later. Should I retract or re-write that post? In any case, the rest of your post indicates we are on the same page. Yes, the event name could be considered misleading. Variations of VALUE_ENTER or VALUE_SUBMIT may have helped. But, that's up to the NI gurus, isn't it.
  13. Thanks for the response, Hoovahh. Understood and agreed regarding the 'Val (Sig)' property. In this case, the LV Developer is forcing LV to trigger an event. However, my expectation from the Front Panel standpoint was for LabVIEW to not even trigger the event, i.e. LV checks for value actually changing before deciding to generate the event internally. IMHO, if one is using 'value change' events, the current implementation pretty much defeats the purpose of the minimum and maximum limits set in the Numeric's properties - depending on data validation requirements, the Developer would be forced to perform a check in the event structure to discard further action. To give you a background, my thought process for this started when I realized some subVI was coercing numeric values coming in even though no 'in range and coerce' equivalent functionality was implemented in its block diagram. That led me to realize that it's obviously not a good practice to validate inputs' range via front panel properties, unless some in-code documentation clearly states so. More importantly, as several sources rightly state, coercing values without alerting the user is not a good practice. Then, I wanted to see if this coercion was OK for front panels meant to be direct user interfaces. Ummm, I guess I refuted my own statement... with the event triggered even when there is no value change, it would after all be good programming to alert the user that a 'limit' has been reached and offer alternatives (instead of 'discarding' further action as I mis-stated above). Thanks! for the mini-discussion.
  14. Hello, I searched within this site and via Google for any related queries. Couldn't find any. Hence this post... Example of Situation: I configured an I8 Numeric with non-default limits in its 'Properties >> Data Entry' window... Minimum of -2 (coerced); Maximum of 2 (coerced). I set up a simple event that looks for 'Value Change' of this Numeric. Expectation: No matter what the 'Increment' value and 'Response to value outside limits' are set to, the 'Value Change' must NOT trigger if the numeric is already at the limit and cannot be changed further. To explain, If current value of Numeric is 2 and I try to increment it, its value must remain at 2 and no event should be triggered. Similarly, with current value of Numeric at -2, if I try to decrement it, its value must remain at -2 and no event should be triggered. What I found was that the value does remain at the limit, but an event is still triggered when the 'Increment' setting is non-zero. Is this normal behavior? Test Numeric Event Triggering.vi coded in LV2014
×
×
  • Create New...

Important Information

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