/*
*** 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
November 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 PortD.0 when a missed-call is detected
- Reply with a status report if a message beginning with "stat" is received
- Toggle PortD.1 and reply with a status report if a "Please Call Me"
  (South African SMS phenomenon) is received.
- Set PortD all on if a message beginning with "on" is received
- Set PortD 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 RG7 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 USB
(receivable by the mikroElektronika USB (HID) Terminal).
*/

/*
*** Board Setup ***
The EasyPIC Fusion v7 board should be set up as follows for this example:
- GSM click or GSM2 click plugged in on mikroBus socket 1
- PortD LEDs on (SW15.5)
*/

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

//#define usb_disable // Disable all USB

//<GSM>
sbit GSM_Pwr_Key at LATC1_bit; // Pin for powering the module on/off
sbit GSM_Pwr_Key_Dir at TRISC1_bit;
sbit GSM_Stat at PORTB.B8; // Indicates if the module is powered on
sbit GSM_Stat_Dir at TRISB8_bit;
//</GSM>

#ifndef usb_disable
//<USB>
char USBin[64];
char USBout[64];
//</USB>
#endif

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

// -- 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)
//PortG.7 input debounce
unsigned int wrdRG7Tmr = 65535;

void Timer1Interrupt() iv IVT_ADDR_T1INTERRUPT {
  // 1ms Interrupt
  // Timer Calculator (http://www.libstock.com/projects/view/398/timer-calculator )
  // can help to calculate the correct values for TMR0H and TMR0L,
  // depending on MCU clock speed
  gsm1msPing();
  if (wrdRG7Tmr < 65535) {wrdRG7Tmr++;}
  T1IF_bit         = 0;
}

#ifndef usb_disable
void USB1Interrupt() iv IVT_ADDR_USB1INTERRUPT {
  USB_Interrupt_Proc();
}
#endif

void Timer1Init(){
  //Prescaler 1:8; PR1 Preload = 8750; Actual Interrupt Time = 1 ms
  T1CON                 = 0x8010;
  T1IE_bit         = 1;
  T1IF_bit         = 0;
  IPC0                 = IPC0 | 0x1000;
  PR1                 = 8750;
}

void setup() {    
  // Setting output frequency to 140MHz
  PLLFBD = 70;             // PLL multiplier M=70
  CLKDIV = 0x0000;         // PLL prescaler N1=2, PLL postscaler N2=2
  // Setting USB frequency to 48MHz
  // Using primary oscillator (8MHz) with APLL
  ACLKCON3 = 0xB4C1;       // Use primary oscillator (8MHz), APLL prescaler N1=2, APLL postscaler N2=2
  ACLKDIV3 = 0x0007;       // APLL multiplier M=24
  // Convert all I/O pins to digital
  ANSELA = 0x00;
  ANSELB = 0x00;
  ANSELC = 0x00;
  ANSELD = 0x00;
  ANSELE = 0x00;
  ANSELG = 0x00;
  
  TRISD = 0x0000; //PortD all outputs
  LATD  = 0x0000; //PortD all off by default
  GSM_Pwr_Key_Dir = 0;
  GSM_Stat_Dir = 1;
  CNPUG7_bit = 1;     //RG7 Weak Pull-Up Enabled
  PPS_Mapping(100, _INPUT,  _U1RX); // Sets pin RP100 (RF4) to be an input,  and maps U1RX to it
  PPS_Mapping(101, _OUTPUT, _U1TX); // Sets pin RP101 (RF5) to be an output, and maps U1TX to it
  Timer1Init();
}

void startup() {
  bitRTCC_Set = 0;
  UART1_Init(9600); // For GSM Module
  gsmInit();
  gsm_MS_Init();
  gsm_Msg_Init(); // Requires GSM_Msg module
  #ifndef usb_disable
  HID_Enable(&USBin, &USBout);
  #endif
}

void UIntToBin(char input, char *output) { // Convert an unsigned integer to a binary string
  unsigned int mask;
  for (mask = 0b1000000000000000; 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;
  UIntToBin(PORTA, dest);
  dest += 16;
  *dest++ = ',';
  strcpy(dest, "LATD:");
  dest += 5;
  UIntToBin(LATD, dest);
}

void msgSend() {
  #ifndef usb_disable
  strcpy(&USBout, "Sending message to ");
  strcat(&USBout, &strDestID);
  strcat(&USBout, ":\r\n");
  HID_Write(&USBout, 64);
  strncpyExNewLine(&USBout, &strMsgSendTxt, 64);
  HID_Write(&USBout, 64);
  #endif
  if (strDestID[0] != 0) {
    if (gsmMsgSendPending()) {gsmMsgSendCancel();} // Cancel any message waiting to be sent
    gsmMsgSend(&strMsgSendTxt, &strDestID); // Send the message
  }
}

void gsmMissedCall(char *OriginatorID) {
  LATD0_bit = !LATD0_bit; // Toggle PortD.0
  if (strDestID[0] == 0) { // If destination ID has not yet been set
                           // then copy it from origin ID (reply to sender)
    strcpy(&strDestID, OriginatorID);
  }
}

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"
    LATD = 0xFFFF;
  } else if (*(MessageText + 1) == 'f') { // Looking for "off"
    LATD = 0x0000;
  } else if (memcmp(MessageText, "stat", 4) == 0) { //Status report
    generateStatusReport(&strMsgSendTxt);
    msgSend();
  } else if (memcmp(MessageText, "please call ", 12) == 0) { // "Please Call Me"
    LATD1_bit = !LATD1_bit;
    generateStatusReport(&strMsgSendTxt);
    msgSend();
  } else if (memcmp(MessageText, "test", 4) == 0) { //Test
    strcpy(&strMsgSendTxt, "GSM Library all ok!");
    msgSend();
  }
}

void gsmEvent(char GsmEventType) {
  char sRTCC[17];
  switch (GsmEventType) {
    case gsmevntPIN_Request:
      // Enter SIM card PIN code
      //strcpy(pstrGsmEventData, "0000");
      break;
    case gsmevntPIN_Fail:
      #ifndef usb_disable
      strcpy(&USBout, "PIN entry failed\r\n");
      HID_Write(&USBout, 64);
      #endif
      break;
    case gsmevntMissedCall:
      gsmMissedCall(pstrGsmEventOriginatorID);
      break;
    case gsmevntMsgRcvd:
      gsmMsgRcvd(pstrGsmEventData, pstrGsmEventOriginatorID);
      break;
    case gsmevntMsgSent:
      #ifndef usb_disable
      strcpy(&USBout, "Message sent\r\n");
      HID_Write(&USBout, 64);
      #endif
      break;
    case gsmevntMsgDiscarded:
    case gsmevntMsgSendFailed:
      #ifndef usb_disable
      strcpy(&USBout, "Message send failed\r\n");
      HID_Write(&USBout, 64);
      #endif
      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)
        #ifndef usb_disable
        strcpy(&USBout, "Date/Time: ");
        RTCC_GenerateString(&dtmGsmEvent, &USBout + 11);
        strcat(&USBout, "\r\n");
        HID_Write(&USBout, 64);
        #endif
        memcpy(&dtmRTCC, &dtmGsmEvent, 6);
        bitRTCC_Set = 1;
      } else {
        #ifndef usb_disable
        strcpy(&USBout, "Date/Time not yet set.\r\n");
        HID_Write(&USBout, 64);
        #endif
      }
      break;
    case gsmevntDateTimeWrite:
      // Set the GSM modules date/time using dtmRTCC
      memcpy(&dtmGsmEvent, &dtmRTCC, 6);
      break;
    case gsmevntIMEI_Read:
      #ifndef usb_disable
      strcpy(&USBout, "IMEI: ");
      strcat(&USBout, pstrGsmEventData);
      strcat(&USBout, "\r\n");
      HID_Write(&USBout, 64);
      #endif
      break;
  }
}

void main() {
  setup();
  startup();
  gsmDateTimeRead();
  while (1) {
    gsmPoll(); // Keep the GSM library running

    // Send a message if RG7 is pulled low
    if ((RG7_bit == 0) && (wrdRG7Tmr > 10000)) {
      strcpy(&strMsgSendTxt, "GSM Lib: RG7 pulled low.");
      msgSend();
      wrdRG7Tmr = 0;
    }
  } // (while)
} // (void)