LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Producer Consumer with a state machine within the consumer

    Hi All,

I have been trying to develop a data acquisition system with the producer consumer architecture.  To the left of the two main loops I initialize the serial port and any constants and variables im using.  I also have an obtain queue VI needed for enqueue and dequeue. Then in the producer loop i have a state machine.  The first state is where I wait for a button press on the front panel to write a GO signal on the serial line which will tell the device connected to the serial port to begin sampling data.  After this button press I go into the next state which is called my read state.

In the read state I use a property node to read all of the available bytes at the serial port and then enqueue this collected data into a queue.  The state machine then is directed to continously go to the read state again and collect more data.

Now this is where my dilemma is......  The consumer loop has the dequeue VI inside it and after this VI i have a state machine (while loop and case structure) which contains the following states
1.  Build Array - build an array from the dequeue element and if there is any left over data from the parsing states it will build an array with the left over data and the dequeued data
2.  Determine packet type - this state looks for the packet type byte(not necessarily the first byte in the message) and also check the next byte (packet length) to ensure that I am at the begininng of this chunk of data.  This state may be a little slow because there can be three different packet types and based on this byte and the packet length it may have to search the array several time to find the valid starting point.  This state also determine the next state to go to based on the packet type.
3 packet type 1 parsing - parse data and store the remaining data it leftOver array.  Go to exit state.
4 packet type 2 parsing - "" ""
5 packet type 3 parsing - "" ""
6 exit - leave this state machine and fall back to the consumer while loop.

After it exit I think it should fall back to the consumer while loop and dequeue more data and enter the state machine again to build a new array with the dequeued data and leftover data.  It seems to work when I trace the execution using the Highlight execution feature, however when I run this all at full speed, it seems to go into the consumers 1st and 2nd states back and forth and not completely go through the state machine.

I tried adding in a delay in the producer loop to give the consumer loop time, but I didnt notice any difference.  Is it possible that my dequeue element is retreiving more data while im still in the state machine, causing the execution to leave the state machine before it finished all states?

Is there a better approach to take to solve this problem. Basically I need to read data at a 1,000,000 baudrate and parse it as quickly as possible so that I can break it up into 3 different packet types, write the data to a file, and graph the actual data (header info removed) in realtime.  I need to also ensure that I am not losing any of the collected data.  Data loss cannnot occur.
0 Kudos
Message 1 of 10
(3,483 Views)

Please post images of your code.

A high level diagram of the protocol you are using will also help.

Is your speed spec in bytes/sec or bits per second?

How long does this app run at those rates?

Is your data saved as binary or text?

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 2 of 10
(3,471 Views)
using usb to serial driver so the baudrate is 1000000 bits per second, 8, N , 1 , no flow control
 
1 byte packet type, 1 byte packet length ,4 bytes payload header, various length payload (based on packet type)

0 Kudos
Message 3 of 10
(3,468 Views)
Well, it certainly sounds like you have thought things through, but as they say, "The devil is in the details...". Would it be possible to post at least a screen shot of your code. Then we would be able to comment more concretely on your proposed architecture.

Mike...

Certified Professional Instructor
Certified LabVIEW Architect
LabVIEW Champion

"... after all, He's not a tame lion..."

For help with grief and grieving.
0 Kudos
Message 4 of 10
(3,466 Views)

Hi Gl,

Obvious one but have you checked for sure that the consumer loop isn't being told to break out of the state machine at the end of state 2? Is there any way an error could be forcing it out (ie is the error cluster wired to the stop terminal somehow). There should be no way that more data appearing on the queue should be able to break into the state machine if it's properly configured unless an error is occurring, maybe a timeout somewhere?

The timing issue (works OK when execution highlighted) almost suggests the producer is filling up the queue and overflowing somewhere - have you specified how many elements the queue can have as a maximum? Is there any timing in the state machine for the consumer?

It sounds like you're going about the structure the right way - it would be useful for you to monitor how many elements are in the queue while you run so that you can see whether the consumer is 'keeping up' with the demand placed upon it. If the queue size continually grows, you will need to find a way to reduce the time taken per iteration in the consumer loop otherwise you will evenually run out of memory.

 You sound like you're doing quite a few operations in the state machine in the consumer, one way to reduce the time taken per iteration is to place the processed data (from the consumer) into a second queue and have a 3rd parallel loop handling time-consuming tasks such as file writing. That way some of the processing time is taken off the consumer and it can keep up with the producer's demand better.

Also, as I think you said in your post, ensure you only open references to things such as files once (outside the main loop) then do the writes inside the state machine, then close off the file once when the application finishes. Opening and Closing references each iteration can add significant time to the loop iteration.

Hope this helps, if you're still having that problem, could you post your code and we can have a look?

Best wishes,

Mark

Certified LabVIEW Architect
0 Kudos
Message 5 of 10
(3,462 Views)
I dont think error clust is wired to the stop terminal.

How do you specify the max queue size.  The only VI i see is Get Queue Status.  Is there another VI to set queue parameters or something.  There is no timing setup in the consumer loop implemented.

Right now I do not have the graphing or writing to a file put into the code at all.  Only the first stages of parsing.  The code should be posted above in the attached zip file.



Thanks,
Gary


0 Kudos
Message 6 of 10
(3,454 Views)

Hi Gary,

Any time I hear "OK in execution highlighting but bad in run-time" I have to think Race-condition.

Please eliminate the use of "dequeed" indicator as a method for passing your data. As your code stands now there is now guarentee the value that was dequeued will be placed in the indicator before the locals are attempting to read from it.

NEXT

Every instance of a local must get a copy of your data so with four copies you are forcing LV to duplicate your data buffer three or four times. Your app will be a challenge to keep up with even if you do everything as efficiently as possible. Extra work will kill you.

Please revise, retry and post back if required.

Just trying to help,

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 7 of 10
(3,443 Views)
Ben,

I havnt had any formal labview training so I guess I dont really understand about passing data efficiently.  I removed the dequeued indicator and replaced it with a wire.

In my build state I store the data in dataArray (1d string array local variable).  Then i go to my next state which is the determine state.  How do I pass the data in dataArray from the build state to the determine state without using the local variable?  I guess I dont see how a wire can be used.

Thanks,
Gary
0 Kudos
Message 8 of 10
(3,437 Views)
Gary wrote "I havnt had any formal labview training so I guess I dont really understand about passing data efficiently. "
 
I guessed as much, but I also got the impression that you are very powerful in some other language.
 
You can use a Shift Register to pass data from one iteration of a loop to another. Shift register can be thought of as "static locals" that are allocated on first call and persist.
 
You will probably have more questions as you go along. This link will give you a list of many threads related to LabVIEW performance.
 
You may also want to review the guidelines for LV diagram style, just to brace yourself for the lectures you will get regarding your examples. So "gird up your loins" and keep asking questions. We have helped many an experienced programmer make the transition to the data-flow paradigm (and if Mike passed his test (I hope, I hope!), you have three architects answering you Q. Mike and I alone have a combined 30 years expreience with LabVIEW).
 
Ben


Message Edited by Ben on 06-20-2008 09:32 AM
Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 9 of 10
(3,430 Views)
A couple of things more to go along with Ben's pointers:
  1. You convert your data from a string, to a U8 array, to a Hex string array in the producer loop, then convert back to a integer to determine what to do with it.  In the process, you create two or three copies of your data, slowing yourself down quite a bit.  The code would be quite a bit more efficient if you left the data as a U8 array.  You can change the format of the controls and indicators to show hex values instead of integer by right clicking on them and selecting Format and Precision...
  2. Your search code is fairly inefficient.  I made a whack at making it a bit better.  See attachment below.
If you continue to run into race conditions, you can debug them using a calls to the Windows debug write sprinkled liberally about your code.  Check out the post here for more information.

Don't let your lack of format LabVIEW training stop you.  The biggest thing to get is the data flow paradigm (aka data is wires, not registers).  Once you get past that and learn how to pass data around using shift registers, queues, events, etc, you are most of the way to mastering LabVIEW.  The rest is just learning the plethora of functionality LabVIEW gives you (yes, I have reimplemented LabVIEW native code more than once in the process of learning).

Let us know if you need more help.
0 Kudos
Message 10 of 10
(3,385 Views)