CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

ring buffer
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kmp84



Joined: 02 Feb 2010
Posts: 349

View user's profile Send private message

ring buffer
PostPosted: Mon Aug 03, 2015 7:37 am     Reply with quote

Hello All,

Any good Example of use ring buffer and interrupt driven serial data manage ? The data is packet oriented like:

<stx><dev_add><func.><...data...><crc><etx>
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 7:40 am     Reply with quote

ex_sisr.c

Shows how to handle a ring buffer, with the 'caveat' that for the supplied code, the buffer _must_ have 'binary' size (16, 32 bytes etc.).

A search here will find many examples of the modifications to this to efficiently handle non binary sizes.

A simple state parser added to support your data format.
kmp84



Joined: 02 Feb 2010
Posts: 349

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 8:06 am     Reply with quote

Ttelmah wrote:
ex_sisr.c

Shows how to handle a ring buffer, with the 'caveat' that for the supplied code, the buffer _must_ have 'binary' size (16, 32 bytes etc.).

A search here will find many examples of the modifications to this to efficiently handle non binary sizes.

A simple state parser added to support your data format.


Hi Mr."Ttelmah"!
I know this example , but if I use I have to have secondary buffer to collect all bytes (linear maybe?) and check for <stx>,<etx> and true <crc>?
If packets are too long (100 byte) I have to have 2 buff with 100 bytes len (too much RAM)

I'm looking for a universal way to manage serial packet data with different length (only receiving, transmit is clear!).
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 8:51 am     Reply with quote

kmp84 wrote:
I'm looking for a universal way to manage serial packet data with different length (only receiving, transmit is clear!).


Yes, you have to have enough buffering to deal with all situations. If you guarantee to process a message in (just) less than the time it takes to receive a new one, then you only need to buffer two messages: the last complete one and the one being received.

When I've done this I've put the state machine in the ISR and saved data into a circular buffer of messages not just characters. I only buffer, and then process, complete, CRC checked, properly framed messages, and flag them for processing once a good message has been received. I don't copy data, it gets stored where it will be later processed: in message buffers.

The other way to do this is as Ttelmah suggests, i.e. to buffer the characters in a ring buffer, then process them in main code using the same state machine approach, and buffer the received messages. One possible problem with this approach is that you may need to copy data from the character buffer to a message buffer, which wastes processor time.

Either way you'll need at least two messages worth of buffering, more if your main loop can get blocked for more than a message's worth. If that means you haven't got enough RAM, then get a bigger PIC. For me, this will be one of the first thins I consider when I decide which PIC to use: How much RAM do I need to buffer and store all the data?
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 1:04 pm     Reply with quote

Realistically though, there should be no reason to actually need the linear buffer. Just use the state machine to decode the data as it arrives.

As another comment, if using the twin buffer approach, don't go moving the data around, just swap the pointers.
kmp84



Joined: 02 Feb 2010
Posts: 349

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 3:07 pm     Reply with quote

Ttelmah wrote:
Realistically though, there should be no reason to actually need the linear buffer. Just use the state machine to decode the data as it arrives.

As another comment, if using the twin buffer approach, don't go moving the data around, just swap the pointers.


If I use only one ring buffer to store packet :
1. How to calc <crc> - byte by byte or after see <etx> byte?
2. Where to do all check inside #int_rda or main loop?
3. maybe func. bgetc() is not necessary in this case?
4. If I see <etx> byte but not see <stx> byte what i have to do?

Thanks for your attention!
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 5:06 pm     Reply with quote

1) CRC must be calculated the same method (algorithm) as the transmitting program does.

2) Normally it's done after the correct 'data stream' has been received. You need all the data not just some of it, so you'd calculate using the 'buffered' data.

3) Data needs to be buffered to compute CRC.

4) You need to destroy the received data (erase), reset counters, etc. and start all over. You need <stx> to 'signal' the 'Start of transmission' and proceed from there.

Also once STX is received, I'd start a 'timer' that is 150% of the total transmission time. If the complete data stream is not received when the 'timer' finishes, flag that transmission as 'bad' and try again (resetting everything of course).

Jay
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 5:34 pm     Reply with quote

Hi,

I hate to throw cold water on you, but I believe this project is too advanced for your apparent capabilities with the 'C' programming language in general, and data transmission protocols, in particular. This is a 'help you' forum, not a 'lead you each step along the way' forum. Doing so is an exercise in frustration for us, and you won't really learn much in the process. Instead, I'd invite you to hang around a while, and work on some less ambitious projects as you come 'up to speed'! There is no easy way to just learn all this stuff quickly, you need to take your time and be methodical about it!
_________________
John

If it's worth doing, it's worth doing in real hardware!
kmp84



Joined: 02 Feb 2010
Posts: 349

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 11:29 pm     Reply with quote

Thanks for all positive suggestion. I will try to do some working code for comment.

Have a good day!
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Mon Aug 03, 2015 11:30 pm     Reply with quote

As a help though, a lot depends on how the check is calculated.
Is this a CRC, or is it an XOR checksum?.

You have put 'CRC', but most checks on quick data like this are XOR checks, not CRC's.
It makes a huge difference to the calculations involved.

The neat thing about XOR checks, is if you include the check byte itself in the sum, the result should be zero. So if this is the case, you reset the check at the STX, and if the check is zero when you reach the ETX, the line is 'good'.
kmp84



Joined: 02 Feb 2010
Posts: 349

View user's profile Send private message

PostPosted: Tue Aug 04, 2015 1:22 am     Reply with quote

Ttelmah wrote:
As a help though, a lot depends on how the check is calculated.
Is this a CRC, or is it an XOR checksum?.

You have put 'CRC', but most checks on quick data like this are XOR checks, not CRC's.
It makes a huge difference to the calculations involved.

The neat thing about XOR checks, is if you include the check byte itself in the sum, the result should be zero. So if this is the case, you reset the check at the STX, and if the check is zero when you reach the ETX, the line is 'good'.


Hi Mr. "Ttelmah",

In my current project this is Not "XOR" check. This is CRC algorithm like this:

Code:
int8 get_checksum(int8 *buffer, int8 bufsize) {
   int8 i;
   int16 AL;
   int8 checksum,temp;
   int1 carry;

   if(bufsize == 0)  // Safety check.  Is the count = 0 ?
      return(0);     // Just return if so

   checksum = 0;

   for(i = 0; i < bufsize; i++) {
    AL = buffer[i];
    AL+=checksum;
    if (AL & 0x100)
         //Here have carry, so rotate one into the byte
         carry=shift_left(&AL,1,1);
    else
         //Else zero
         carry=shift_left(&AL,1,0);
    //Carry is now the bit that came out the bottom   
    if (carry==0)
       AL^=0xDD;
    temp=make8(AL,0); //Get LSB
    if (temp<224)
       checksum=temp;
    else
       checksum=temp-224;
   }
   return checksum;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Tue Aug 04, 2015 3:53 am     Reply with quote

That is not a terribly 'good' checksum. The key thing about a checksum is that all bit patterns should have close to similar probability, so for a one byte check you get close to a 255 in 256 chance that you will see an error. That calculation does not do this.

However that being said, it is easy to handle for receive.

Just perform the calculation one byte 'behind' as you exit the decoding state machine. This way the CRC will not have been included in the sum, when you get to ETX.
kmp84



Joined: 02 Feb 2010
Posts: 349

View user's profile Send private message

PostPosted: Tue Aug 04, 2015 5:14 am     Reply with quote

I have made small test program (for comment), but this is not exactly ring type :

Code:



#include <18F2420.h>
//#include <18F2525.h>
#fuses H4,NOPROTECT,NOWDT,NOLVP,PUT,BROWNOUT,MCLR,NOFCMEN
//#use delay(clock=11059200) // HS->11.0592 Mhz
#use delay(clock=29491200)   // H4->29.4912 Mhz (PLL from 7.3728Mhz)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,PARITY=N,BITS=8,STOP=1,errors)

#define stxPC 0xE2      //stx PC(Master)
#define etxPC 0xE3      //stx PC(Master)
#define dev_add  0x01   //device address

#define RXBUFF_SIZE   64
//#define TXBUFF_SIZE   32

BYTE rxBuff[RXBUFF_SIZE];
BYTE index=0;

int1 fl_begin=FALSE;
int1 fl_end=FALSE;
BYTE crc=0;

#int_rda
void serial_isr() {
   int8 temp_byte;
   temp_byte=getc();
   
   if(temp_byte==stxPC)
   {
      index=0;                      // Clear Index     
      fl_begin=TRUE;                // Set fl_begin
      rxBuff[index++]=temp_byte;    // Get stxPC byte     
   }
   else if(fl_begin)
   {
      rxBuff[index++]=temp_byte;    //  Get bytes...
      if(temp_byte==etxPC)
         fl_end=TRUE;               // set fl_end
     
      if(index>RXBUFF_SIZE)         // If buff Full
      {
         index=0;                   // Clr Index.!
         fl_begin=FALSE;            // Clr fl_begin.!
         fl_end=FALSE;              // Clr fl_end!
      }     
   }
}


/***********Check Packet****************/
void get_packet(void){
   static unsigned int8 i;
   if(fl_end)
   { 
      i++;  // inc. packet counter.
      if(rxBuff[0]==stxPC)
      {
         if(rxBuff[2]==dev_add)
         {
               if(rxBuff[index-1]==etxPC)
               {
                  printf("Packet %u: OK.!\n\r",i);
                  //putc(0xF6);
               }
         }
      }
      fl_begin = fl_end = FALSE;  // Clr. Flags.   
   }
}

void main (){
   
   SETUP_ADC(ADC_OFF);
   SETUP_CCP1(CCP_OFF);
   SETUP_CCP2(CCP_OFF);
   setup_vref(FALSE);
   setup_comparator(NC_NC_NC_NC);
   
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   
   for(;;){
      // inf. loop...
      get_packet();
   }
}
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Tue Aug 04, 2015 8:46 am     Reply with quote

Questions:

How does the code 'know' where the data block ends?.
What has to happen for the different commands?.

There is a big problem with the CRC calculation. As written, it can generate an ETX character. This could be disastrous.
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Tue Aug 04, 2015 8:52 am     Reply with quote

Hi,

Your code is really messy, hard to follow, and contains a lot of unnecessary duplication. And, not only is is 'not exactly' a ring buffer, it's *completely* not a ring buffer!

If it were me, I'd concentrate on reading in the command string first, and not worry about the CRC until this part is completely bomb-proof! Take a look at this thread for some ideas on how to implement a linear buffer:

http://www.ccsinfo.com/forum/viewtopic.php?t=54142

This (relatively) simple scheme has served me well for a number of years in thousands of units in-the-field.

John
_________________
John

If it's worth doing, it's worth doing in real hardware!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group