/********************************************************************************************************************/
/*
LED flashes:
After turn on: 1sec = GSM modult turn on pin is pulled. Effect: GSM module starts flashin in about 1s in an 1 flasn6s rate

Short flashes: 
1 - "AT" command succesful
2 - "AT+CREG=1" command succesful
4 - "ATD+36302167922;" command succesful
5 - "ATH;" command succesful
6 - On sidestand since timeout (default = 1hour) power being turned off

10 - "AT" command 10x not received "OK" 
12 - "AT+CREG=1" command 10x not received "OK"
14 - "ATD+36302167922;" command 10x not received "OK"
15 - "ATH;" command 10x not received "OK"
16 - state machine error
        sprintf(Transmit_string,"ATH");
        sprintf(Required_answer,"OK");
        send_command(5,15,1000);


*/
/***********************************************************************************************************************/

/*
Version history: 

2022.10.06. - initial version

*/


#include <xc.h>
#include <stdio.h>
#include <string.h>
#include <C:\Program Files\Microchip\xc8\v2.31\avr\avr\include\avr\interrupt.h>


#define bit_set(port_address,bit_serial)   ((port_address) |= (1 << bit_serial))
#define bit_clear(port_address,bit_serial) ((port_address) &= ~(1 << bit_serial))
#define bit_get(port_address,bit_serial)   ( ((port_address) & (1 << bit_serial))?1:0)


#define POWER_OFF                          bit_clear(PORTD,PORTB6)
#define POWER_ON                           bit_set(PORTD,PORTB6)

#define GSM_START_0                        bit_clear(PORTB,PORTB0)
#define GSM_START_1                        bit_set(PORTB,PORTB0)

//#define nSIDESTAND                         bit_get(PORTC,PORTC0)
#define nSIDESTAND                         bit_get(PINC,PINC0)

#define LED_OFF                            bit_clear(PORTB,PORTB5)
#define LED_ON                             bit_set(PORTB,PORTB5)

#define TIMER0_10MS                        156

#define FOSC                               16000000 // Clock Speed
#define BAUD                               9600
#define MYUBRR                             103      //FOSC/16/BAUD-1  value taken from table in datasheet

#define RECEIVE_TIMEOUT                    300      

volatile unsigned short it_counter;
volatile unsigned short i;
volatile unsigned short blink_count;
volatile unsigned short timeout_counter;
char                    Transmit_string[100];
char                    Receive_string[100];
char                    Required_answer[100];
char                    string_tmp[100];
unsigned short          c;
unsigned char           tmp;
unsigned short          str_i,str_s;
unsigned char           str_found;
unsigned long          Wait_for_active_counter;          
unsigned long          Wait_for_turnoff_counter;

/* into eeprom */
unsigned long          Wait_for_active_time;       /* default: 3min=18000, max: 11930hour=4e9 */
unsigned long          Wait_for_turnoff_time;      /* default: 1hour=720000, max: 11930hour=4e9 */


enum Main_State_Type
{
  MAIN_STATE_STARTUP,
  MAIN_STATE_CALLING,
  MAIN_STATE_PASSIVE,
  MAIN_STATE_WAIT_FOR_ACTIVE,
  MAIN_STATE_ACTIVE
} Main_State;

void wait_10ms(unsigned short wait_time_10ms)
  {
  TCNT2 = 0;
  it_counter = 0;
  while(it_counter < wait_time_10ms);                                
  }  


void init()
  {

  /* initialize system power ON/!OFF pin */
  bit_set(DDRD,DDD6);
  POWER_ON;

  /* initialize GSM module start pin */
  bit_set(DDRB,DDB0);
  GSM_START_0;

  
  /* initialize LED pin */
  bit_set(DDRB,DDB5);                                      /* portB5 = out = LED drive                             */
  LED_ON;
  LED_OFF;

  /* initialize nSIDESTAND input */
  bit_clear(DDRC,DDC0);
  
  /* interrupt */
  bit_set(SREG,7);                                        /* global interrupt enable                                      */
  
  /* configure 8 bit timer/counter2 for timebase interrupt */
  bit_clear(TCCR2B,WGM22);                                 /* mode = CTC / OCRA                                           */
  bit_set(TCCR2A,WGM21);
  bit_clear(TCCR2A,WGM20);
  OCR2A = TIMER0_10MS;
  bit_set(TIMSK2,OCIE2A);                                  /* Timer/Counter0 CompareA Interrupt Enable                    */
  bit_set(TCCR2B,CS22);                                    /* start timer, prescaler = 1024                               */
  bit_set(TCCR2B,CS21);
  bit_set(TCCR2B,CS20);

  // init USART
  bit_set(DDRD,DDD1);                                      /* portD1 = out = TxD                             */
  bit_set(PORTD,PORTD1);
  bit_clear(PORTD,PORTD1);
  UBRR0H = (unsigned char)((MYUBRR)>>8);                        /*Set baud rate */
  UBRR0L = (unsigned char)MYUBRR;
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);                           /* Enable receiver and transmitter */
  UCSR0C = (3<<UCSZ00);                                     /* Set frame format: 8data, 1stop bit */
  
  LED_ON;
  wait_10ms(100);                                           /* wait 1s for the GSM module to start up                      */ 
  LED_OFF;
  
  // start GSM Module
  //GSM_START_1;
  //wait_10ms(100);                                           /* wait 1s                                                    */
  //GSM_START_0;
  //wait_10ms(250);                                           /* wait for serial port to initialize     */

  Main_State = MAIN_STATE_STARTUP;
  Wait_for_active_counter = 0;
 // Wait_for_active_time = 18000;
 // Wait_for_turnoff_time = 720000;
/* test */
Wait_for_active_time = 18000; /*3min*/
Wait_for_turnoff_time = 720000; /* 1hour */
  }


void USART_Transmit_Byte(char data)
{
  while (!(UCSR0A & (1<<UDRE0)));                            /* Wait for empty transmit buffer */
  UDR0 = data;                                              /* Put data into buffer, sends the data */
}

void USART_Transmit_crlf()
{
  USART_Transmit_Byte(13);
  USART_Transmit_Byte(10);
}


void USART_Transmit_String(char *Tr_string)
  {
  
  c = 0;
  while(Tr_string[c] != '\0')  
    {
    USART_Transmit_Byte(Tr_string[c]);
    c++;
    }
  }

unsigned char USART_Receive(void)
{
  while (!(UCSR0A & (1<<RXC0)) && timeout_counter > 0);        /* Wait for data to be received */
  if(timeout_counter>0)
  {
    return UDR0;                                                 /* Get and return received data from buffer */
  }  
  else 
  {
    return '\0';
  }
}

void blinks(unsigned short blink_count)
  {
  for(;blink_count>0;blink_count--)
    {
    TCNT2 = 0;
    LED_ON;
    it_counter = 0;
    while(it_counter < 10);
    TCNT2 = 0;
    LED_OFF;
    it_counter = 0;
    while(it_counter < 30);
    }

  }


SIGNAL(TIMER2_COMPA_vect)
{
  TCNT2 = 0;
  it_counter++;
  
  if(timeout_counter>0)
  {
    timeout_counter--;
  }
  
  if(Wait_for_active_counter>0)
  {
    Wait_for_active_counter--;
  }
  
  if(Wait_for_turnoff_counter>0)
  {
    Wait_for_turnoff_counter--;
  }
  
}

void start_timeout10ms(unsigned short timeout10ms)
{
  timeout_counter = timeout10ms;
}

/* searches "find" in "search"
return: 
   1 if found
   0 if not found */
unsigned char str_in_str(char *search, char *find)
{
  
  str_found = 0;
  
  if(strlen(find) > strlen(search))
  {
    return(0);                                                          /* not found*/
  }
  for(str_s=0;str_s<=strlen(search)-strlen(find);str_s++)  
    {
    str_found = 1;
    for(str_i=0;str_i<strlen(find);str_i++)
      {
      if(search[str_s+str_i] != find[str_i])     
        {
        str_found=0;  
        }
      }
    if(str_found == 1)  
      {
        return(1);
      }
    }
  return(0);
}

void send_command(unsigned char success_blink, unsigned char fail_blink, unsigned short delay_between_attempts)
{
unsigned char answer_received;
unsigned char retry_counter;
unsigned char receive_string_end;
    
  retry_counter = 0;
  answer_received = 0;                                                         /* good answer received */
  while(answer_received == 0)
  {

    USART_Transmit_String(Transmit_string);
    USART_Transmit_crlf();
    
    
    start_timeout10ms(RECEIVE_TIMEOUT);                                          /* timeout for reply */
    i=0;
    receive_string_end = 0;
    Receive_string[0] = '\0';
    while(receive_string_end == 0)                                              /* string received or timeout */
    {
      Receive_string[i] = USART_Receive();

      if(Receive_string[i] == 0x0a && i>=3 && Receive_string[i-3] == 'O'&& Receive_string[i-2] == 'K') /*string end with 'OK' */
      {
        receive_string_end = 1;
      }
      else if(Receive_string[i] == '\0') /* timeout */
      {
        receive_string_end = 1;
      }

      i++;
    }

/*if(success_blink == 2)
    USART_Transmit_String(Receive_string);
  */  
    
    if(Receive_string[i-1] != '\0' && str_in_str(Receive_string,Required_answer) )
    {
      answer_received = 1;
      blinks(success_blink);
      
//      sprintf(string_tmp,"%s", Receive_string);
//      USART_Transmit_String(string_tmp);

    }
    else
    {
//      sprintf(string_tmp,"n%s", Receive_string);
//      USART_Transmit_String(string_tmp);

      
      retry_counter++;
      wait_10ms(delay_between_attempts);
      if(retry_counter >= 10)
      {
        blinks(fail_blink);
        wait_10ms(600);
        POWER_OFF;
        while(1);
      }
    }
  }

}  


int main(void)
  {


  init();	
  
  /* Wait until "AT" reply is "OK" 10 attempts, error handling: soft powerswitch off, idle loop until power off.  */
  sprintf(Transmit_string,"AT");
  sprintf(Required_answer,"OK");
  send_command(1,11,1000);                                 /* 1=success, 10=fail, 50=delay between attempts */
  wait_10ms(100);
  
  sprintf(Transmit_string,"AT+CREG=1");
  sprintf(Required_answer,"OK");
  send_command(2,12,1000);                                 
  wait_10ms(1000);
  
  sprintf(Transmit_string,"ATD+36302167922;");
  sprintf(Required_answer,"OK"); 
  send_command(4,14,1000);
  
  
  Main_State = MAIN_STATE_CALLING;
  
  while(1)
    {
    switch (Main_State)
      {
      /* make the call for 55s */
      case MAIN_STATE_CALLING:
        wait_10ms(5500);
  
        sprintf(Transmit_string,"ATH");
        sprintf(Required_answer,"OK");
        send_command(5,15,1000);
        wait_10ms(100);
        Main_State = MAIN_STATE_PASSIVE;
      break;
      
      /* bike is in use. Able to receive SMS command. Wait for sidestand */
      case MAIN_STATE_PASSIVE:
        if(nSIDESTAND == 0)
        {
          Wait_for_active_counter = Wait_for_active_time;
          Main_State = MAIN_STATE_WAIT_FOR_ACTIVE;
          wait_10ms(10);
        }
      break;

      /* Wait "wait_for_active_time" default: 3min to activate alarm */    
      case MAIN_STATE_WAIT_FOR_ACTIVE:
        if(Wait_for_active_counter == 0)
        {
          Wait_for_turnoff_counter = Wait_for_turnoff_time;
          Main_State = MAIN_STATE_ACTIVE;
        }
        if(nSIDESTAND == 1)
        {
          Main_State = MAIN_STATE_PASSIVE;
          wait_10ms(10);
        }


      break;
      /* On sidestand. Turnoff_time (1hour) not passed. */
      case MAIN_STATE_ACTIVE:
        if(nSIDESTAND == 1)
        {
          sprintf(Transmit_string,"ATD+36302167922;");
          sprintf(Required_answer,"OK");
          send_command(4,14,1000);
           
          Main_State = MAIN_STATE_CALLING;
        }

        if(Wait_for_turnoff_counter == 0)
        {
          blinks(6);
          wait_10ms(600);
          POWER_OFF;
          while(1);
        }
      break;

      default:
        blinks(16);
        wait_10ms(600);
        POWER_OFF;
        while(1);
      break;
      }
    }   
  
  }
