Get Adobe Flash player
FacebookTwitterGoogle+
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

According to Moore's Law, microchips double in power every 18 to 24 months.
 

Help us stay online:

small donate

Data-stream-1-600When communicating with other devices,  we often need to parse incoming data stream to recognize predefined format of commands, for example, when using GPRS modem or GPS receiver. There are many examples when data stream parsing is a must have! In previous articles we have seen how to define strings (these will be predefined commands) in FLASH memory space and in that way save RAM memory for variables.
Now we will show how to detect when useful information have been received and extract received data.

 


As starting point we will use previously given AVR UART single character example.
All data received from UART is stored in circular buffer named rx_buffer. Data will be sent continuously and microcontroller must detect when command is received.
When microcontroller receives command “output:” it should detect it and execute something depending on byte right after that command:
“output:1” – send back “yes”
“output:0” – send back “no”

We will be using next standard C function embedded in Codevision:

char *strstrf(char *str1, char flash *str2)      
Searches the string str1, located in SRAM, for the first occurrence of the string str2, located in FLASH.
If there is a match, returns a pointer to the character in str1 where str2 begins.
If there is no match, returns a NULL pointer.

unsigned int strlenf(char flash *str)
Returns the length of the string str located in FLASH, excluding the null terminator.

Here is first version of Codevision code that will help us do this task. You can download this code HERE.

/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.4a Advanced
Automatic Program Generator
© Copyright 1998-2009 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project : 
Version : 
Date    : 12/8/2011
Author  : NeVaDa
Company : 
Comments:
Chip type               : ATmega8535
Program type            : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 128
*****************************************************/
#include <mega8535.h>
#include <string.h>
#ifndef RXB8
#define RXB8 1
#endif
#ifndef TXB8
#define TXB8 0
#endif
#ifndef UPE
#define UPE 2
#endif
#ifndef DOR
#define DOR 3
#endif
#ifndef FE
#define FE 4
#endif
#ifndef UDRE
#define UDRE 5
#endif
#ifndef RXC
#define RXC 7
#endif
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART Receiver buffer
#define RX_BUFFER_SIZE 20
char rx_buffer[RX_BUFFER_SIZE];
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;
unsigned char my_variable; //variable used for receiving data from UART
const unsigned char command[] ="output:";
//command located in FLASH memory.
const char answer1[] ="YES\n\r";
//answer located in FLASH memory.
const char answer0[] ="NO\n\r";
//answer located in FLASH memory.
unsigned char character_received=0,temp;
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   { 
   character_received=1;//enables parsing only if something is received
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Declare your global variables here
    
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
for (temp=0;temp<RX_BUFFER_SIZE;temp++)
   rx_buffer[temp]='x';           //fils receive buffer at beggining witk x
while (1)
      {
      // Place your code here  
      if (character_received==1)  //code executes only if something is received
        {       
        character_received=0;    //next time this is executed is when next character is received in ISR
        puts("\n\r Buffer contains: ");
        puts(rx_buffer) ;   
        puts("\n\r command (stored in FLASH) is received from this part of buffer: "); 
        //part of the string \n\r is just for eneter for better visibility in terminal 
        if(strstrf(rx_buffer,command)) 
            //searches the string str1 for the first occurrence of the string str2.
            //If there is a match, returns a pointer to the character in str1 where str2 begins.
            //If there is no match, returns a NULL pointer.
            puts(strstrf(rx_buffer,command));
        else
             puts("NULL");
        puts("\n\r command (stored in RAM) is received from this part of buffer: ");  
       if(strstr( rx_buffer,"output:"))   
       //searches the string str1, located in SRAM, for the first occurrence of the string str2, located in FLASH.
        //If there is a match, returns a pointer to the character in str1 where str2 begins.
        //If there is no match, returns a NULL pointer  
            puts(strstr( rx_buffer,"output:"));
        else
             puts("NULL");     
        putchar(13);
       }
      };
}

When “output:1” is typed in terminal you will get next logs:

Buffer contains: oxxxxxxxxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: NULL
 Buffer contains: ouxxxxxxxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: NULL
 Buffer contains: outxxxxxxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: NULL
 Buffer contains: outpxxxxxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: NULL
 Buffer contains: outpuxxxxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: NULL
 Buffer contains: outputxxxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: NULL
 Buffer contains: output:xxxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: output:xxxxxxxxxxxxx
 Buffer contains: output:1xxxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: output:1xxxxxxxxxxxx
 Buffer contains: output:12xxxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: output:12xxxxxxxxxxx
 Buffer contains: output:123xxxxxxxxxx
 command (stored in FLASH) is received from this part of buffer: output:123xxxxxxxxxx
}

so you can see how buffer gets filled and command is detected.

Now we will modify the code slightly to get desired functionality.

 /*****************************************************
This program was produced by the
CodeWizardAVR V2.04.4a Advanced
Automatic Program Generator
© Copyright 1998-2009 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project : 
Version : 
Date    : 12/8/2011
Author  : NeVaDa
Company : 
Comments:
Chip type               : ATmega8535
Program type            : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 128
*****************************************************/
#include <mega8535.h>
#include <string.h>
#ifndef RXB8
#define RXB8 1
#endif
#ifndef TXB8
#define TXB8 0
#endif
#ifndef UPE
#define UPE 2
#endif
#ifndef DOR
#define DOR 3
#endif
#ifndef FE
#define FE 4
#endif
#ifndef UDRE
#define UDRE 5
#endif
#ifndef RXC
#define RXC 7
#endif
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART Receiver buffer
#define RX_BUFFER_SIZE 20
char rx_buffer[RX_BUFFER_SIZE];
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;
unsigned char my_variable; //variable used for receiving data from UART
const unsigned char command[] ="output:";
//command located in FLASH memory.
const char answer1[] ="YES\n\r";
//answer located in FLASH memory.
const char answer0[] ="NO\n\r";
//answer located in FLASH memory.
unsigned char character_received=0;
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   { 
   character_received=1;//enables parsing only if something is received
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Declare your global variables here
  void clear_buffer(void)
  {  
  unsigned char temp;
  for (temp=0;temp
   rx_buffer[temp]=0;           //fils receive buffer at beggining witk x       
   rx_wr_index=0;   //when we empty buffer we should also reset circular buffer pointers to say it is empty.
   rx_rd_index=0;
   rx_counter=0;
  }
    
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
clear_buffer();//fils receive buffer at beggining witk 0
while (1)
      {
      // Place your code here  
      if (character_received==1)  //code executes only if something is received
            {       
            character_received=0;    //next time this is executed is when next character is received in ISR
            //puts("\n\r Buffer contains: ");
            //puts(rx_buffer) ;   
            //puts("\n\r command (stored in FLASH) is received from this part of buffer: "); 
            //part of the string \n\r is just for eneter for better visibility in terminal 
            if(strstrf(rx_buffer,command))
                { 
                //searches the string str1 for the first occurrence of the string str2.
                //If there is a match, returns a pointer to the character in str1 where str2 begins.
                //If there is no match, returns a NULL pointer.         
                //if (strstrf(rx_buffer,command)+strlenf(command))
                if(*(strstrf(rx_buffer,command)+strlenf(command))=='1')
                    {
                    putsf(answer1);
                    clear_buffer();
                    }  
               if(*(strstrf(rx_buffer,command)+strlenf(command))=='0')
                    {
                    putsf(answer0); 
                    clear_buffer();
                    }
                }
            }
      };
}

And now when typed in terminal you get correct answers

parsing v2

 You can download Codevision command parsing project with complete source code that is shown above from THIS LINK

There still remains small problem that buffer is circular so this kind of parsing will not recognize if part of command is at the end of the buffer and part at the beginning of buffer. Circular buffers work this way since they work with write and read index positions that go in circle over buffer.

This is easily solved by shifting receiving buffer. This makes receiving buffer FIFO type. This is a slow process, but it is simple way to solve the problem. Other option is to modify parsing functions to work with circular buffer which is more complex job to do and if you are beginner I would not recommend it.