Page 1 of 1

CAN FIFO CB34EX

Posted: Tue Oct 12, 2010 11:28 am
by kidproquo
Hello Experts,

I am trying to use the CB34EX as a remote CANBUS monitor. I have looked at the CAN Serial example and have successfully ran it on the hardware. I am trying to adapt it to work with Ajax requests by putting the CAN Serial code in the Ajax callback function. Here's the code inside the Ajax Callback. As you can see, all it does is print the FIFO content whenever there's an Ajax request. I will later change it to send the CAN message as a JSON object.


Code: Select all

void AjaxCallback(int sock, const char* url)
{
  CanRxMessage can_msg( &fifo, 1 ); //Wait up to 1 tick
  if ( can_msg.IsValid() )
  {
      BYTE buffer[8],tension[2];
      BYTE len;
      DWORD id;
      len = can_msg.GetData( buffer, 8 );
      id = can_msg.GetId();
      iprintf( "Received a CAN message of %d bytes from ", len );
      if ( IsNBIdExt( id ) )
      {
         iprintf( "Extended ID=%ld or 0x%07X\r\n",
                  NbToExtId( id ),
                  NbToExtId( id ) );
      }
      else
      {
         iprintf( "ID=%d or 0x%03X\r\n", NbToNormId( id ), NbToNormId( id ) );
      }

      iprintf( "Data = [" );
		for ( int i = 0; i < len; i++ )
		{
		   if ( ( buffer[i] < ' ' ) || ( buffer[i] > 128 ) )
		   {
			  iprintf( "{%d}", buffer[i] );
		   }
		   else
		   {
			  iprintf( "%d", buffer[i] );
		   }
		}
		iprintf( "]\r\n" );
            }
}
How do I flush the FIFO whenever there's an Ajax request? I want to be able to poll for the latest messages. Is this the right way to go? My plan is to have multiple FIFOs that will be populated with CAN messages of certain IDs which can be then streamed out to the web from the Ajax callback.

Please advise.

Regards,
Kid

Re: CAN FIFO CB34EX

Posted: Tue Oct 12, 2010 12:05 pm
by lgitlitz
Hi,

If you want to retrieve all the messages in the CAN fifo then you need to have all of this code in a loop. Just put everything in a while(1) loop. You need to be able to flush the FIFO faster then you can read messages and 1 tick is much slower then the CAN bus. To fix this change "CanRxMessage can_msg( &fifo, 1 );" to "CanRxMessage can_msg( &fifo, DONT_WAIT );". This will avoid being stuck in the loop forever if CAN messages keep rolling in. Have an else condition for the "if ( can_msg.IsValid() )". This is where you want to have a break; to escape the while loop once the FIFO is fully flushed.

-Larry

Re: CAN FIFO CB34EX

Posted: Tue Oct 12, 2010 12:39 pm
by pbreed
If you look at the can code...
CanRxMessage::CanRxMessage( OS_FIFO *pFifo, WORD timeout )
{
if ( timeout == DONT_WAIT )
{
pData = ( PrivateCanData * ) OSFifoPendNoWait( pFifo );
}
else
{
pData = ( PrivateCanData * ) OSFifoPend( pFifo, timeout );
}
}


You can make the call by passing in DONT_WAIT for the timeout and it will return immediately...
That way it does not whait 1 time tick if ther eis no message....

Paul

Re: CAN FIFO CB34EX

Posted: Tue Oct 12, 2010 6:22 pm
by kidproquo
Larry, Paul, thanks for the replies.

So, if I initialize with

Code: Select all

CanInit( 250000, 0/* Mask value of 0 receives everything */, 4 )
, all messages should be received by the FIFO when I do this

Code: Select all

int chan1 = RegisterCanRxFifo( NormToNbId( 0x123 ), &fifo );
.

What happens to the FIFO if the

Code: Select all

 CanRxMessage can_msg( &fifo, DONT_WAIT );
call is done at slow intervals (say 200ms requests from the Ajax call in the browser)? How many messages get stored in the FIFO? From the documentation I see that FIFOs are dynamically assigned. Hence would it just blow up the heap? Or does the fact that the FIFO is a global variable help?

I am confused on how to go about my implementation. I have many CAN bus messages at different update intervals (100 ms, 500 ms, 1000 ms). Whenever I get an Ajax request, I want to be able to take a "snapshot" of the CAN messages. If the snapshot does not contain a certain message ID, I plan to just keep sending the previously encountered value for that message ID. I can do all that logic inside if I can understand what happens to the FIFO when it isn't read during the 200ms before the next Ajax request comes in. I hope I am not sounding too stupid :-)

Regards,
Kid

Re: CAN FIFO CB34EX

Posted: Wed Oct 13, 2010 6:40 am
by stevep
The CAN bus read should go in the main loop so that every time you loop through, you check for new CAN messages. If you get a new message, store the data you need in a variable.

When the web page refreshes, read the current value from the variable, not directly from the FIFO.

Re: CAN FIFO CB34EX

Posted: Wed Oct 13, 2010 7:16 am
by kidproquo
Steve,

That's another approach that I am considering. My only question in that case is wouldn't I need synchronization? What if the main loop is writing to the variable right when I am reading it in the Ajax callback? Will the read block automatically? I think I will need to look into Chapter 15 (Protecting Shared Data Structures) in the programmer's manual.

Regards,
Kid

Re: CAN FIFO CB34EX

Posted: Wed Oct 13, 2010 10:36 am
by pbreed
I'd make the CAN read a while so each time through it reads ALL the results in the buffer.


Paul

Re: CAN FIFO CB34EX

Posted: Wed Oct 13, 2010 11:28 am
by lgitlitz
The CAN FIFO is statically allocated and it is defined in canif.cpp. The default size of the FIFO is also defined in this file, on the network products is "#define CAN_DATA_STORE_SIZE (512)". This means there can be up to 512 messages stored in the FIFO. Each element in the FIFO takes 20 bytes, so the 512 default size uses about 10KB of RAM. With 8MB of total RAM you can easily increase this FIFO by a factor of 10 or more. Still if you are reading from the FIFO at a slower speed then you are receiving messages then you will overflow now matter how much space is available. Once the FIFO is full messages are tossed away but it will not crash your app or overrun the heap.

You first suggested to have the AJAX page call a function that reads from the FIFO. This is OK as long as you are positive that the page is updating faster then you are receiving CAN data. If not then your messages being posted will be old and you can possibly lose some CAN data if the FIFO overflows. The better way to do this is to have a shared set of variables. Then anytime a message comes in you write these variables and the AJAX page updates by reading these variables. The negative with this method is when your page updates slower then the incoming CAN data is received then those messages will not be displayed. At least you know that the current refresh will always be showing the latest CAN message. You also will not have to worry about overflowing the FIFO and losing incoming CAN messages.

What I would do is create a separate task for reading the CAN FIFO. Make this task a higher priority (lower task number) then your user main task. This task should look just like your initial code but have all of it in a while(1) loop. To get the CAN message call:

Code: Select all

CanRxMessage can_msg( &fifo, TICKS_PER_SECOND * 5 );

This will block the task for up to 5 seconds, if it times out then the message will not be valid and you can post an error. Whenever you receive a CAN message this task will start running no matter how long the timeout value is. If the CAN message is valid you should write to the shared variables that the AJAX is using. The section of code that modifies the variables and the section of code that reads the variables should be protected with a global OSCrit section. This will ensure that the variables are never read in the middle of a write.

Re: CAN FIFO CB34EX

Posted: Thu Oct 14, 2010 11:46 pm
by kidproquo
Thanks a lot! That was very well explained. Much appreciated.

Re: CAN FIFO CB34EX

Posted: Sun Mar 06, 2011 7:15 am
by oleg_osov
Hello, hardware gurus!

First of all - I'm using NNDK-MOD5234-KIT.

I would like to get an explanation of a CAN example:

Code: Select all

int chan1 = RegisterCanRxFifo( NormToNbId( 0x123 ), &fifo );
In all examples and in canif.cpp I see this 0x123 id. I'm a bit puzzled - which Id should I use to receive all messages from the bus? 0x0 or 0x7FF ?

And a couple other questions:
If I have main loop where I read all messages with the code:

Code: Select all

CanRxMessage can_msg( &fifo, TICKS_PER_SECOND * 5 );
what is the best way to send RTR message? Create a new CanRxMessage instance with:

Code: Select all

CanRxMessage( DWORD id, WORD timeout );
like

Code: Select all

CanRxMessage rtr_msg( 0x482, 5 );
Is it a good approach? And why do I need to wait until I get a response on my RTR message? I think it's better when I have a main loop where I read *all* messages from the bus?