02-18-2011 03:35 PM
I am using an NI USB-8473 CAN module to communicate between a pc and an embedded microprocessor. Sending data to the micro works fine and I can recieve single messages from the micro on pc through the 8473. My problem is I can't seem to get it to wait for a new message. I am using Visual C++ and the ncwaitforstate function as follows:
Status = ncWaitForState(TxRx, NC_ST_READ_AVAIL, NC_DURATION_INFINITE, &state);
Status = ncRead(TxRx, sizeof(ReceiveBuf),(void *)ReceiveBuf);
My interpretation of how this function works is that the first line should wait for an infinite period of time until a new frame is available, but it doesn't behave that way. Once I have recieved a message, it will no longer wait for new data and will give me old data from a previous message. It is definitely not waiting to recieve new data. So it's hit or miss whether the data I read using ncRead is new or not. Many times it is not.
Am I using this function properly and if not, what is the proper way to wait until new data has arrived before reading it. According to the manual ncWaitForState() is it.
Traver
02-21-2011 10:44 AM
I believe you are correct in your understanding of the function. You can look at this knowledge base, and page 610 of 705 in this manual to make sure you are using it correctly, but if I understand what you are saying I think it is correct. The manual does mention some things like you are not able to call it at the same time from multiple threads with the same object handle. It would be worth your time to take a look.
If you are using it exactly as specified, you may want to see what is getting sent by your micro controller that could be setting off the wait. You could try capturing the data with NI-Spy to see what may be triggering the wait.
03-29-2011 08:14 AM
I have tried everything. The C program (not the microcontroller) is refusing to wait for new data to come in using ncwaitforstate. Is there some flag that has to be manually reset to signify that data is old has already been read? I thought this would happen automatically when reading using ncread.
03-30-2011 04:34 PM
I have been reading the manual a little closer. Let me show you what I have found.
Using Queues
There are two basic types of NI-CAN queues: the read queue and the write
queue. NI-CAN uses the read queue to store incoming network data items
in the order they arrive. You access the read queue using ncRead to obtain
the data.
State Transitions
The NC_ST_READ_AVAIL state transitions from false to true when NI-CAN
places a new data item into an empty read queue, and remains true until you
read the last data item from the queue and the queue is empty.
Empty Queues
When you read an empty queue, the previous data item is returned
again. For example, if you call ncRead when NC_ST_READ_AVAIL is false,
the data from the previous call to ncRead is returned again, along with the
CanWarnOldData warning. If no data item has yet arrived for the read
queue, a default data item is returned, which consists of all zeros. You
should generally wait for NC_ST_READ_AVAIL prior to the first call to
ncRead.
Are you seeing the warning saying that the queue is empty, and that is why you are getting the first message repeated?
Also I haven't found any references to whether the ncRead deletes from the queue or if it needs to be deleted with a seperate call.
That maybe a reason as well.
04-05-2011 03:19 PM
I have read those sections too.
"If no data item has yet arrived for the read
queue, a default data item is returned, which consists of all zeros. You
should generally wait for NC_ST_READ_AVAIL prior to the first call to ncRead."
Isn't this what waitForState is for? According to the previous statement, the program should wait until new data is available using ncWaitForState (for an infinite period of time if I choose NC_DURATION_INFINITE), but it is not doing that. Will data in the read queue be considered NC_ST_READ_AVAIL even if it has already been read? This brings me back to the question: must I manually delete items from the read queue after I read them?
04-07-2011 03:41 PM
I have read through the manual a few times now, and I still don't exactly see what is going wrong.
From my understanding it could be 3 things, you are sending more than one message that is the same, the wait is being used incorrectly and you are calling read on the empty queue which will return the old message and a warning, or read in not clearing the buffer like I believe it should.
I would like you to try using the ncReadMult to see if you get more than one message, or if it clears the queue as we expect.
04-15-2011 09:21 AM
Ok, I think I have a handle on what's going on. You are right in that ncWaitForState is working correctly. The issue is making a distinction between the hardware queue and the software queue in C. The hardware queue is getting ahead of itself (it is receiving extra messages). The next time I waitforState, there is a message already in there from a previous operation.
The question is now: is there a way to purge the hardware queue before I ask for a response so I know the message pertains to the current operation? Is there a better way deal with transmit and responses so I know the message sitting in the read queue is the one I want? I will perhaps try ncreadMult and see if that gives me more flexibility.
04-15-2011 03:47 PM
Here is what I've learned if this helps anyone:
There are two entities to be concerned with in sending and receiving messages: the network interface (hardware), and the frames, queues, and other variables you create in software. Both have read and write queues with lengths that can be set in software. The hardware queues are handled automatically. The hardware read queue is a FIFO containing frames that came across the bus. The frames it receives can be filtered by the hardware using NC_ATTR_CAN_MASK_XXX and NC_ATTR_CAN_COMP_XXX. If these are set to DONTCARE, any frames coming on the bus will be read into the queue.
ncRead will basically copy the hardware receive buffer [0] frame to whatever frame holder you have created in your software (NC_TYPE_CAN_FRAME_TIMED for example). This is where ncWaitForState comes in. You can use ncWaitForState to make sure the data in the hardware receive buffer [0] is new. The problem I was running into at first is that my hardware read buffer had 0 length. This causes the value in the hardware receive FIFO [0] to be overwritten with every new frame that comes in. If the device on the other end is too fast (as was the case in my hardware), you will lose data and ncWaitForState can't tell the difference.
There are two options to read data and not lose anything: Set the hardware read queue to a decent length. There are some recommended values elsewhere on these forums, but ideally, it will be determined by the speed of your application. Use ncRead, or ncReadMult to copy the data from the hardware to your software receive entity. ncRead will give you the output of the hardware FIFO and automatically place the next oldest frame at the output for the next ncRead. ncReadMult will copy the entire contents of the hardware receive buffer to a software receive buffer you have created. It is then up to you to handle the data. Reading from your software buffer will not automatically act as a FIFO like the hardware buffer. You must handle this on your own if you want it to behave this way.
ncWaitForState only tells you if data is available, not how old it is, or if it has been overwritten. When you get the data using ncRead or ncReadMult, you must manage it yourself in software.