![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
kmp84
Joined: 02 Feb 2010 Posts: 345
|
ring buffer |
Posted: Mon Aug 03, 2015 7:37 am |
|
|
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> |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Aug 03, 2015 7:40 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
kmp84
Joined: 02 Feb 2010 Posts: 345
|
|
Posted: Mon Aug 03, 2015 8:06 am |
|
|
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!). |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Aug 03, 2015 8:51 am |
|
|
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? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Aug 03, 2015 1:04 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
kmp84
Joined: 02 Feb 2010 Posts: 345
|
|
Posted: Mon Aug 03, 2015 3:07 pm |
|
|
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! |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Mon Aug 03, 2015 5:06 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Aug 03, 2015 5:34 pm |
|
|
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! |
|
![](templates/subSilver/images/spacer.gif) |
kmp84
Joined: 02 Feb 2010 Posts: 345
|
|
Posted: Mon Aug 03, 2015 11:29 pm |
|
|
Thanks for all positive suggestion. I will try to do some working code for comment.
Have a good day! |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Aug 03, 2015 11:30 pm |
|
|
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'. |
|
![](templates/subSilver/images/spacer.gif) |
kmp84
Joined: 02 Feb 2010 Posts: 345
|
|
Posted: Tue Aug 04, 2015 1:22 am |
|
|
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;
} |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Tue Aug 04, 2015 3:53 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
kmp84
Joined: 02 Feb 2010 Posts: 345
|
|
Posted: Tue Aug 04, 2015 5:14 am |
|
|
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();
}
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Tue Aug 04, 2015 8:46 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Tue Aug 04, 2015 8:52 am |
|
|
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! |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|