/*
*** 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 STM32M4 clicker is currently set up to perform various
actions when a message is received, missed call is detected,
or the T1 or T2 buttons are pressed - 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 GSM Library 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 LED1 (LD1 - PortA.1) when a missed-call is detected
- Toggle LED2 (LD2 - PortA.2) if a
  "Please Call Me" (South African SMS phenomenon) is received.
- Set both LEDs on if a message beginning with "on" is received,
  or set a specific LED on if "on1" or "on2" is received.
- Set both LEDs off if a message beginning with "off" is received,
  or set a specific LED off if "off1" or "off2" is received.
- Send a message to the number stored in strDestID if button T1 or button T2
  is pressed
  (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).
*/

//#define usb_disable // Disable all USB

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

//<GSM>
sbit GSM_Pwr_Key at ODR5_GPIOB_ODR_bit;
sbit GSM_Stat at IDR0_GPIOA_IDR_bit; // Indicates if the module is powered on
#ifdef gsm_debug_state
char *gsmDebugStateStrPtr;
#endif
//</GSM>

//<Buttons_LEDs>
sbit btn1 at IDR0_GPIOC_IDR_bit;
sbit btn2 at IDR1_GPIOC_IDR_bit;
sbit led1 at ODR1_GPIOA_ODR_bit;
sbit led2 at ODR2_GPIOA_ODR_bit;
//</Buttons_LEDs>

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

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

// -- Variables --
//GSM SMS
char strMsgSendTxt[161]; //Message text to send
char strDestID[15] = ""; // Destination ID (will be taken from first
                         // missed-call / SMS if left blank)
//Button inputs
unsigned int wrdButtonTmr = 65535;

void USB0Interrupt() iv IVT_INT_OTG_FS {
  #ifndef usb_disable
  // <USB Interrupt>
  USB_Interrupt_Proc();
  // </USB Interrupt>
  #endif
}

void Timer2_interrupt() iv IVT_INT_TIM2 {
  // <Timer2 Interrupt> // 1ms Interrupt
    // Timer Calculator (www.libstock.com/projects/view/398/timer-calculator)
    // can help to calculate the correct setup,
    // depending on MCU clock speed
    gsm1msPing();
    if (wrdButtonTmr < 65535) {wrdButtonTmr++;}
    TIM2_SR.UIF = 0; // Clear interrupt flag
  // </Timer2 Interrupt>
}

void Timer2_init(){
  RCC_APB1ENR.TIM2EN = 1;
  TIM2_CR1.CEN = 0;
  TIM2_PSC = 1;
  TIM2_ARR = 59999;
  NVIC_IntEnable(IVT_INT_TIM2);
  TIM2_DIER.UIE = 1;
  TIM2_CR1.CEN = 1;
}

void setup() {
  GPIO_Digital_Input(&GPIOC_BASE, _GPIO_PINMASK_0 | _GPIO_PINMASK_1); // Button inputs
  GPIO_Digital_Output(&GPIOA_BASE, _GPIO_PINMASK_1 | _GPIO_PINMASK_2); // LED outputs
  GPIO_Digital_Input(&GPIOA_BASE, _GPIO_PINMASK_0); // GSM Stat Input
  GPIO_Digital_Output(&GPIOB_BASE, _GPIO_PINMASK_5); // GSM Pwr_Key Output
  #ifndef usb_disable
  HID_Enable(&USBin,&USBout); // Enable HID communication
  //delay_ms(1000); // Give USB time to initialise
  #endif
  Timer2_init();
}

void startup() {
  #ifdef gsm_debug_state
  #ifndef usb_disable
  gsmDebugStateStrPtr = &USBout;
  #endif
  #endif
  led1 = 0;
  led2 = 0;
  UART4_Init(9600);
  gsmInit();
  gsm_MS_Init();
  gsm_Msg_Init(); // Requires GSM_Msg module
  bitRTCC_Set = 0;
}

#ifdef gsm_echo_int_rx
void gsmUartRxEcho(char *UartRxLine) {
  #ifndef usb_disable
  strncpyExNewLine(&USBout, UartRxLine, 64);
  HID_Write(&USBout, 64);
  #endif
}
#endif


#ifdef gsm_debug_state
void gsmDebugStateStrReady() {
  #ifndef usb_disable
  HID_Write(&USBout, 64);
  #endif
}
#endif

void msgSend() {
  #ifndef usb_disable
  // Debug output
  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) {
  led1 = !led1; // Toggle LED1
  if (strDestID[0] == 0) { // If the destination ID has not yet been set then
    strcpy(&strDestID, OriginatorID); // Copy it from the originator ID
  }
}

void gsmMsgRcvd(char *MessageText, char *OriginatorID) {
  if (strDestID[0] == 0) { // If the destination ID has not yet been set then
    strcpy(&strDestID, OriginatorID); // Copy it from the originator ID
  }                                   // (reply to sender)
  if (gsmMsgJustArrived() == 1) {
    // If the message has just arrived, then the time/date extracted from it
    // are probably good
    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"
    LED1 = 1;
    LED2 = 1;
  } else if (*(MessageText + 1) == 'f') { // Looking for "off"
    LED1 = 0;
    LED2 = 0;
  } else if (memcmp(MessageText, "please call ", 12) == 0) { // "Please Call Me"
    LED2 = !LED2;
  }
}

void gsmEvent(char GsmEventType) {
  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() {
  char tmp;
  setup();
  startup();
  gsmDateTimeRead();
  while (1) {
    gsmPoll();

    // Send a message if a button is pressed
    if (wrdButtonTmr > 10000) {
      if (btn1 == 0) {
        strcpy(&strMsgSendTxt, "Button T1 pressed.");
        msgSend();
        wrdButtonTmr = 0;
      } else if (btn2 == 0) {
        strcpy(&strMsgSendTxt, "Button T2 pressed.");
        msgSend();
        wrdButtonTmr = 0;
      }
    }
  } // (while)
} // (void)