#include <mega16.h>
#include <alcd.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>

flash const char SIM_CMT[]  = "CMT";

#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)

// USART Receiver buffer
#define RX_BUFFER_SIZE 128
char rxBuffer[RX_BUFFER_SIZE];

uint8_t rxBufferIndex = 0;
uint8_t rxBufferOverflow = 0;
uint8_t rxLineFlag = 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)
   {
      rxBuffer[rxBufferIndex] = data;
      
      if (rxBufferIndex != 0 && 
          data == '\n' &&
          rxBuffer[rxBufferIndex - 1] == '\r') {
          if (rxBufferIndex > 1) {
            rxLineFlag = 1;
          }
          else {
            rxBufferIndex = 0;
          }          
      }
      
      if (++rxBufferIndex == RX_BUFFER_SIZE) {
        rxBufferOverflow = 1;
        rxBufferIndex = 0;
      }
   }
}


void main(void)
{
// Declare your local variables here
uint8_t inReceiveMessage = 0;
char phone[14];
char message[32];
// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Port C initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
UCSRB=(1<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
UCSRC=(1<<URSEL) | (0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
UBRRH=0x00;
UBRRL=0x33;

// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTA Bit 0
// RD - PORTA Bit 1
// EN - PORTA Bit 2
// D4 - PORTA Bit 4
// D5 - PORTA Bit 5
// D6 - PORTA Bit 6
// D7 - PORTA Bit 7
// Characters/line: 16
lcd_init(16);

// Global enable interrupts
#asm("sei")

while (1)
      {
        if (rxLineFlag) {                          
          char* pDot;
          rxBuffer[rxBufferIndex - 2] = '\0';
          rxBufferIndex = 0;
          rxLineFlag = 0;
          // read message
          if (inReceiveMessage) {
            strcpy(message, rxBuffer);
            lcd_gotoxy(0, 0);
            lcd_puts(message); 
            inReceiveMessage = 0;
          }
          // check '+' & find ':'
          else if (rxBuffer[0] == '+' && (pDot = strchr(rxBuffer, ':')) != NULL) {
            uint16_t len = (uint16_t) pDot - (uint16_t) &rxBuffer[1];  
            // check CMT     
            if (strncmpf(&rxBuffer[1], SIM_CMT, len) == 0) {
               char* pStart = strchr(++pDot, '"');
               if (pStart != NULL) {
                  char* pEnd = strchr(++pStart, '"');
                  if (pEnd != NULL) {
                    len = (uint16_t) pEnd - (uint16_t) pStart;
                    // read phone
                    strncpy(phone, pStart, len);
                    phone[len + 1] = '\0';
                    lcd_gotoxy(0, 1);
                    lcd_puts(phone);
                    inReceiveMessage = 1;
                  }
               }  
            } 
          }                        
          else {
            lcd_clear();
            lcd_gotoxy(0, 0);
            lcd_puts(rxBuffer);
          }              
        }
      }
}
