/*
*** Brief ***
- Handle various events from the GSM Library in the gsmEvent routine
  (such as missed-call, message received, etc)
- Send messages using gsmMsgSend routine
! Text message functionality requires the GSM_Msg library module,
  available from Dizzy Enterprises
This example code for the EasyPIC7 is currently set up to perform various 
actions when a msg is received, missed call is detected, or RB7 is pulled low - 
please see the below overview for details.
!!! Please see the warning below regarding msgs stored in SIM card memory !!!  
*/

/*
*** Overview ***
Software written by Dane du Plooy
http://www.dizzy.co.za
September 2014

!!! Warning !!!
The code uses the SIM card memory for drafting and reading messages.
This is done in order to maximise reliability.
If the SIM card message memory is not currently empty, then
any messages stored on the SIM card will be processed and deleted, 
and any drafts saved on the SIM card will be sent.
Please check that this will not cause any problems
before running this code with your SIM card.
(Perhaps copy any relevant messages from SIM card memory to phone memory.)

Currently, the software will:
(please note that all received SMSs are converted to lower-case by the software, 
and are thus not case sensitive)
- Toggle PortC.1 when a missed-call is detected
- Reply with a status report if a message beginning with "stat" is received
- Toggle PortC.2 and reply with a status report if a "Please Call Me"
  (South African SMS phenomenon) is received.
- Set PortC.1-PortC.5 all on if a message beginning with "on" is received
- Set PortC.1-PortC.5 all off if a message beginning with "off" is received  
- Reply with "GSM Library all ok!" if a message beginning with "test" is rcvd
- Send a message to the number stored in strDestID if RB7 is pulled low
  (if strDestID is not explicitly set then it will be taken from the first
  missed call or SMS received)
  
Debug information is output via UART2
*/

/*
*** Board Setup ***
The EasyPIC7 board should be set up as follows for this example:
- Power supply jumper (J5) in appropriate position for GSM module
  (3.3V if you want to be safe)
- GSM click or GSM2 click plugged in on mikroBus socket 1
The rest of the board should be in it's default configuration (as it is when
originally purchased):
- PortC LEDs on (SW3.3)
- All pull-up / pull-down resistors off
To view debug messages:
- Connect the board to a PC using one of the UART (serial comms) connectors
- Set SW1 and SW2 for RX and TX on RD7 and RD6
- Set J3 and J4 appropriately
- Serial comms can be viewed using the mikroE USART terminal / Hyper Terminal / etc
If an LCD is connected then the last incoming event (message or missed call)
will be displayed on it
*/

//#include "GSM.h"
//#include "Str.h"
#include "RTCC.h"

//<GSM>
sbit GSM_Pwr_Key at LATE1_bit; // Pin for powering the module on/off
sbit GSM_Pwr_Key_Dir at TRISE1_bit;
sbit GSM_Stat at PORTA.B2; // Indicates if the module is powered on
sbit GSM_Stat_Dir at TRISA2_bit;
//</GSM>

//<RTCC>
TDateTime dtmRTCC;
bit bitRTCC_Set;
//</RTCC>

//<LCD> // Setup for 2x16 LCD
sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
//</LCD>

// -- Variables --
//GSM SMS
char strMsgSendTxt[161]; //Message text to send
char strDestID[15] = ""; // Destination ID 
                         // Enter a mobile number of your choice above
                         // (will be taken from first missed-call / SMS 
                         // if left blank) 
//PortB.7 input debounce
unsigned int wrdRB7Tmr = 65535;         

void interrupt() { 
  // <Timer0 Interrupt>
  if (T0IF_bit) { // 1ms Interrupt
    // Timer Calculator (www.libstock.com/projects/view/398/timer-calculator)
    // can help to calculate the correct values for TMR0H and TMR0L,
    // depending on MCU clock speed
    TMR0H = 0x00;
    TMR0L = 0x06;
    //UART_Set_Active(&UART1_Read, &UART1_Write, &UART1_Data_Ready, &UART1_Tx_Idle);
    UART_Rd_Ptr = &UART1_Read;
    UART_Wr_Ptr = &UART1_Write;
    UART_Rdy_Ptr = &UART1_Data_Ready;
    UART_Tx_Idle_Ptr = &UART1_Tx_Idle;
    gsm1msPing();
    if (wrdRB7Tmr < 65535) {wrdRB7Tmr++;}
    T0IF_bit = 0; // Clear interrupt flag
  }
  // </Timer0 Interrupt>
}

void setup() {
  TRISA = 0b11111111; //PortA all inputs
  TRISB = 0b11000000; //PortB all outputs, except RB6 & RB7
  TRISC = 0b10000001; //PortC all outputs, except RC7 (RX) and RC0 (RI)
  TRISD = 0b10000000; //PortD all outputs, except RD7 (RX)
  LATC  = 0b00000000; //PortC all off by default  
  LATD  = 0b00000000; //PortD all off by default
  GSM_Pwr_Key_Dir = 0;
  GSM_Stat_Dir = 1;
  ANSELA = 0b00000000; //All pins digital
  ANSELB = 0b00000000; //All pins digital
  ANSELC = 0b00000000; //All pins digital
  ANSELD = 0b00000000; //All pins digital      
  RBPU_bit = 0; //PortB Weak Pull-Ups Enabled
  IPEN_bit = 0; //Interrupt priority disable
  GIE_bit = 1; //Global interrupt enable
  PEIE_bit = 1; //Peripheral interrupt enable
  T0CON = 0b11000100; //Timer0 On, 8-bit, internal clock, 1:32 prescaler
  T0IE_bit = 1; //Enable Timer0 overflow interrupts
}   

void startup() {
  bitRTCC_Set = 0;              
  UART2_Init(115200); // For output of debug messages
  UART1_Init(9600); // For GSM Module
  gsmInit();
  gsm_MS_Init();
  gsm_Msg_Init(); // Requires GSM_Msg module
  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Cmd(_LCD_CURSOR_OFF);      
}

void ByteToBin(char input, char *output) { // Convert a byte to a binary string
  char mask;
  for (mask = 0b10000000; mask != 0; mask = mask >> 1) {
    if (input & mask) *output = '1'; else *output = '0';
    output++;
  }
  *output = 0; // Mark the end of the string
}

void generateStatusReport(char *dest) { // Generate a string indicating the
                                        // port states
  strcpy(dest, "PORTA:");
  dest += 6;
  ByteToBin(PORTA, dest);
  dest += 8;
  *dest++ = ',';
  strcpy(dest, "PORTB:");
  dest += 6;
  ByteToBin(PORTB, dest);
  dest += 8;
  *dest++ = ',';
  strcpy(dest, "LATC:");
  dest += 5;
  ByteToBin(LATC, dest);
}

void msgSend() {   
  UART2_Write_Text("Sending message to ");
  UART2_Write_Text(&strDestID);
  UART2_Write_Text(":\r\n");
  UART2_Write_Text(&strMsgSendTxt);
  UART2_Write_Text(":\r\n");
  if (strDestID[0] != 0) {    
    if (gsmMsgSendPending()) {gsmMsgSendCancel();} // Cancel any message waiting to be sent
    gsmMsgSend(&strMsgSendTxt, &strDestID); // Send the message
  }  
}

void gsmMissedCall(char *OriginatorID) {
  LATC1_bit = !LATC1_bit; // Toggle PortC.1
  if (strDestID[0] == 0) { // If destination ID has not yet been set
                           // then copy it from origin ID (reply to sender)
    strcpy(&strDestID, OriginatorID);
  }
  LCD_Cmd(_LCD_CLEAR);
  LCD_Out(1,1,OriginatorID);
  LCD_Out(2,1,"(Missed Call)");
}

void gsmMsgRcvd(char *MessageText, char *OriginatorID) {
  if (strDestID[0] == 0) { // If destination ID has not yet been set
                           // then copy it from origin ID (reply to sender)
    strcpy(&strDestID, OriginatorID);
  }        
  if (gsmMsgJustArrived() == 1) {
    // If the message has just arrived, then the time/date extracted from it
    // are probably good (not old)
    if (!bitRTCC_Set) {
      memcpy(&dtmRTCC, &dtmGsmEvent, 6);
      // Write the date/time from the message to the GSM modules internal RTCC
      gsmDateTimeWrite();
    }
  }
  lcase(MessageText); // Convert the entire message to lower case
  // Interpret the message data
  if (*(MessageText + 1) == 'n') { // Looking for "on"
    LATC = 0xFF;
  } else if (*(MessageText + 1) == 'f') { // Looking for "off"
    LATC = 0x00;
  } else if (memcmp(MessageText, "stat", 4) == 0) { //Status report 
    generateStatusReport(&strMsgSendTxt);
    msgSend();   
  } else if (memcmp(MessageText, "please call ", 12) == 0) { // "Please Call Me" 
    LATC2_bit = !LATC2_bit;
    generateStatusReport(&strMsgSendTxt);  
    msgSend();
  } else if (memcmp(MessageText, "test", 4) == 0) { //Test 
    strcpy(&strMsgSendTxt, "GSM Library all ok!");
    msgSend();     
  } 
  LCD_Cmd(_LCD_CLEAR);
  LCD_Out(1,1,OriginatorID);
  if (strlen(MessageText) > 16) {
    *(MessageText+16) = 0; // Trim string to fit on LCD if necessary
  }
  LCD_Out(2,1,MessageText);  
}

void gsmEvent(char GsmEventType) {
  char sRTCC[17];
  switch (GsmEventType) {
    case gsmevntPIN_Request:
      // Enter SIM card PIN code
      //strcpy(pstrGsmEventData, "0000");
      break;
    case gsmevntPIN_Fail:
      UART2_Write_Text("PIN entry failed\r\n");
      break;
    case gsmevntMissedCall:
      gsmMissedCall(pstrGsmEventOriginatorID);
      break;
    case gsmevntMsgRcvd:
      gsmMsgRcvd(pstrGsmEventData, pstrGsmEventOriginatorID);
      break;
    case gsmevntMsgSent:
      UART2_Write_Text("Message sent\r\n");
      break;
    case gsmevntMsgDiscarded:
    case gsmevntMsgSendFailed:
      UART2_Write_Text("Message send failed\r\n");
      break;
    case gsmevntDateTimeRead:
      if (dtmGsmEvent.Year > 10) { // If the GSM modules date/time is valid
                                   // (if it has been set previously, or
                                   // aquired from the GSM network)
        // Output the date/time via UART2
        UART2_Write_Text("Date/Time: ");
        RTCC_GenerateString(&dtmGsmEvent, &sRTCC);
        UART2_Write_Text(&sRTCC);
        UART2_Write(13);
        UART2_Write(10);
        //Uncomment the below to display date/time on the LCD
        //LCD_Cmd(_LCD_CLEAR);
        //LCD_Out(1,1,"RTCC Set:");
        //LCD_Out(2,1,&sRTCC);
        memcpy(&dtmRTCC, &dtmGsmEvent, 6);
        bitRTCC_Set = 1;
      } else {
        UART2_Write_Text("Date/Time not yet set.\r\n");
      }
      break;
    case gsmevntDateTimeWrite:
      // Set the GSM modules date/time using dtmRTCC
      memcpy(&dtmGsmEvent, &dtmRTCC, 6);
      break;
    case gsmevntIMEI_Read:
      UART2_Write_Text("IMEI: ");
      UART2_Write_Text(pstrGsmEventData);
      UART2_Write_Text("\r\n");
      break;
  }
}

void main() {
  setup();
  startup();
  gsmDateTimeRead();
  Lcd_Out(1,1,"  GSM Library   ");
  Lcd_Out(2,1,"www.dizzy.co.za ");  
  while (1) {
    UART_Set_Active(&UART1_Read, &UART1_Write, &UART1_Data_Ready, &UART1_Tx_Idle);
    gsmPoll(); // Keep the GSM library running
    
    // Send a message if RB7 is pulled low
    if ((RB7_bit == 0) && (wrdRB7Tmr > 10000)) {
      strcpy(&strMsgSendTxt, "GSM Lib: RB7 pulled low.");
      msgSend();
      wrdRB7Tmr = 0;
    }    
    
    // Power down the GSM module if RB6 is held low
    gsmPowerSetOnOff(RB6_bit);
  } // (while)
} // (void)