01-26-2018 10:17 AM
I am working on a vi that will use an external switch(button) hooked up to digital in on a daq. when the button is pressed and held it starts recording the time until the button is released. The time is displayed on the front panel, when the button is released the last value is still displayed. When the button is pressed and held again it starts counting again from 0.
I am trying to make it so that after recording an amount of time, the value will be written to a text file. This file serves as a history backup in case the timer is restarted before the value can be written down. I need the values to be added to the next row in the file and not overwrite previous values. What is the best way to do this?
I've attached what I have so far which is the timing part. In place of the external switch I am using a switch on the front panel.
01-27-2018 04:10 PM
Have you looked at the File I/O functions? There are many formats you can use to output your data, but if you are doing "intermittent logging", formatting your value into a string that has "useful human-readable information" (such as "The value of the Frammistat on 1/27/2018 at 5:32 pm was 6.257") might be suitable.
The first question is "Do you want to open a file, add lines to it at various times, then close it, with a unique file being written for each run of the program", or do you want to have a "Frammistat Log File", open it when you have a value to write, write the value at the end of the file, and then close the file so its value will be preserved if your program crashes? You can do either, depending on how you open the file, whether or not you go to the end of the (already-existing) file before doing the write, etc.
Give it a try. Write a little test program that, say, writes values of random numbers once a second for 10 seconds, and see what you get. Recall that to be "human-readable" you need to write a Text file, and you need to write your data in String formats (it's tricky for humans to read the bits of a Dbl and have them make sense).
Bob Schor
01-29-2018 07:26 AM - edited 01-29-2018 07:28 AM
I want to open it when I have a value to write, write the value at the end of the file, and then close the file so its value will be preserved if my program crashes. what will be written is the date, time, and the station number. The tricky part is I am trying to figure out how to do this only when the signal goes from 1 to 0.
Also there will be 30 similar inputs with their own timers that I would like to write to the same file. Right now I am working towards getting a single instance of this running but need to keep in mind that there need to be many more inputs eventually.
01-29-2018 08:07 AM
Open the file with the "Open or Create" option (so it will work both with a "first write" where no file-by-that-name exists and "append-write" where the file already exists), Get File Size (so you can "move to the end"), Set File Position (to move to the end), Write, and Close.
If you follow my suggestion to (at least, initially) write a Text file so that it is "human-readable" (and you can be sure you are doing it right), you need to make sure that you write an "end-of-string" (<CR><LF>, or \r\n) at the end so each entry stands on its own line. A simple way to do this (one I use) is to take the string (without the CR-LF) and pass it through "build array" -- writing an array of strings to a Text File writes each string on its own line!
To handle multiple timers writing independently to the same file (a situation I encountered last week), you can handle that with a Producer/Consumer architecture. Instead of passing your String to a "Write" sub-VI (that does the Open/GoTo End/Write/Close sequence), put it in a Queue (the Producer). The Consumer empties the Queue, creating an array of all the entries it finds (this can be a little tricky -- you can also simply take one element off the Queue) and sends this array to the Write sub-VI. This way, your "Producers" take almost no time to "write" their results (they're only putting it on a Queue), while your Consumer uses "free time" to do all of the file I/O (which should be pretty quick), letting the Queue "buffer" simultaneous requests (on a first-come, first-serve basis) from the 30 inputs you may eventually have.
Bob Schor
01-29-2018 08:16 AM - edited 01-29-2018 08:16 AM
You don't need to get the file size unless you care about it for some reason.
You can just set the file position to the end.
01-29-2018 08:20 AM
Thanks for the advice Bob,
How about when triggering it to write? I want it to write when the timer stops or right before it restarts. I was thinking of building a state machine for this. Is this an efficient way of doing this and how does that fit with the producer/consumer architecture?
01-29-2018 12:04 PM
State Machines are often a Good Idea. If you have a State that you enter when "Timer Off", or a State that you enter to "Turn Timer On", you could make it the "Producer" by having it put the String that you want written to the Log on the Log Queue (to the Consumer).
Bob Schor
01-29-2018 12:08 PM
As (almost) always, I completely agree with RavensFan. I was actually looking at a routine I use that uses File Size for an Error Log, which could get "hung" generating, say, a million errors and creating a humongous file. So I use the Size to decide "Is it time to panic?", but you don't need to go that route, and the "End" method is definitely easier (and probably faster).
Bob Schor
01-30-2018 10:13 AM
Ok so I have changed my timer into a state machine that goes from "off" to "on" when the button turns on. turning the switch off sends it from "on" to "write" then immediately back to "off". The "write" case concatenates the date/time station number and elapsed time and sends it to the queue. I then turned all that into a subvi.
This is my first time doing producer consumer and working with the queue functions. I mostly copied an example and everything seems to be working fine. If anyone has time to take a peak at it for any potential problems that would be great.