#include "sms.h" /********************************************************** Method sends SMS number_str: pointer to the phone number string message_str: pointer to the SMS text string return: ERROR ret. val: --------------- -1 - comm. line to the GSM module is not free -2 - GSM module didn't answer in timeout -3 - GSM module has answered "ERROR" string OK ret val: ----------- 0 - SMS was not sent 1 - SMS was sent an example of usage: GSM gsm; gsm.SendSMS("00XXXYYYYYYYYY", "SMS text"); **********************************************************/ char SMSGSM::SendSMS(char *number_str, char *message_str) { char ret_val = -1; byte i; char end[2]; end[0]=0x1a; end[1]='\0'; /* if (CLS_FREE != gsm.GetCommLineStatus()) return (ret_val); gsm.SetCommLineStatus(CLS_ATCMD); ret_val = 0; // still not send */ // try to send SMS 3 times in case there is some problem for (i = 0; i < 1; i++) { // send AT+CMGS="number_str" gsm.SimpleWrite(F("AT+CMGS=\"")); gsm.SimpleWrite(number_str); gsm.SimpleWriteln("\""); #ifdef DEBUG_ON Serial.println("DEBUG:SMS TEST"); #endif // 1000 msec. for initial comm tmout // 50 msec. for inter character timeout if (RX_FINISHED_STR_RECV == gsm.WaitResp(1000, 500, ">")) { #ifdef DEBUG_ON Serial.println("DEBUG:>"); #endif // send SMS text gsm.SimpleWrite(message_str); gsm.SimpleWriteln(end); //_cell.flush(); // erase rx circular buffer if (RX_FINISHED_STR_RECV == gsm.WaitResp(7000, 5000, "+CMGS")) { // SMS was send correctly ret_val = 1; break; } else continue; } else { // try again continue; } } gsm.SetCommLineStatus(CLS_FREE); return (ret_val); } /********************************************************** Method sends SMS to the specified SIM phonebook position sim_phonebook_position: SIM phonebook position <1..20> message_str: pointer to the SMS text string return: ERROR ret. val: --------------- -1 - comm. line to the GSM module is not free -2 - GSM module didn't answer in timeout -3 - specified position must be > 0 OK ret val: ----------- 0 - SMS was not sent 1 - SMS was sent an example of usage: GSM gsm; gsm.SendSMS(1, "SMS text"); **********************************************************/ char SMSGSM::SendSMS(byte sim_phonebook_position, char *message_str) { char ret_val = -1; char sim_phone_number[20]; ret_val = 0; // SMS is not send yet if (sim_phonebook_position == 0) return (-3); if (1 == gsm.GetPhoneNumber(sim_phonebook_position, sim_phone_number)) { // there is a valid number at the spec. SIM position // => send SMS // ------------------------------------------------- ret_val = SendSMS(sim_phone_number, message_str); } return (ret_val); } /********************************************************** Method finds out if there is present at least one SMS with specified status Note: if there is new SMS before IsSMSPresent() is executed this SMS has a status UNREAD and then after calling IsSMSPresent() method status of SMS is automatically changed to READ required_status: SMS_UNREAD - new SMS - not read yet SMS_READ - already read SMS SMS_ALL - all stored SMS return: ERROR ret. val: --------------- -1 - comm. line to the GSM module is not free -2 - GSM module didn't answer in timeout OK ret val: ----------- 0 - there is no SMS with specified status 1..20 - position where SMS is stored (suitable for the function GetSMS()) an example of use: GSM gsm; char position; char phone_number[20]; // array for the phone number string char sms_text[100]; position = gsm.IsSMSPresent(SMS_UNREAD); if (position) { // read new SMS gsm.GetSMS(position, phone_num, sms_text, 100); // now we have phone number string in phone_num // and SMS text in sms_text } **********************************************************/ char SMSGSM::IsSMSPresent(byte required_status) { char ret_val = -1; char *p_char; byte status; if (CLS_FREE != gsm.GetCommLineStatus()) return (ret_val); gsm.SetCommLineStatus(CLS_ATCMD); ret_val = 0; // still not present switch (required_status) { case SMS_UNREAD: gsm.SimpleWriteln(F("AT+CMGL=\"REC UNREAD\"")); break; case SMS_READ: gsm.SimpleWriteln(F("AT+CMGL=\"REC READ\"")); break; case SMS_ALL: gsm.SimpleWriteln(F("AT+CMGL=\"ALL\"")); break; } // 5 sec. for initial comm tmout // and max. 1500 msec. for inter character timeout gsm.RxInit(5000, 1500); // wait response is finished do { if (gsm.IsStringReceived("OK")) { // perfect - we have some response, but what: // there is either NO SMS: // OK // or there is at least 1 SMS // +CMGL: ,,,,[,,] // OK status = RX_FINISHED; break; // so finish receiving immediately and let's go to // to check response } status = gsm.IsRxFinished(); } while (status == RX_NOT_FINISHED); switch (status) { case RX_TMOUT_ERR: // response was not received in specific time ret_val = -2; break; case RX_FINISHED: // something was received but what was received? // --------------------------------------------- if(gsm.IsStringReceived("+CMGL:")) { // there is some SMS with status => get its position // response is: // +CMGL: ,,,,[,,] // OK p_char = strchr((char *)gsm.comm_buf,':'); if (p_char != NULL) { ret_val = atoi(p_char+1); } } else { // other response like OK or ERROR ret_val = 0; } // here we have gsm.WaitResp() just for generation tmout 20msec. in case OK was detected // not due to receiving gsm.WaitResp(20, 20); break; } gsm.SetCommLineStatus(CLS_FREE); return (ret_val); } /********************************************************** Method reads SMS from specified memory(SIM) position position: SMS position <1..20> phone_number: a pointer where the phone number string of received SMS will be placed so the space for the phone number string must be reserved - see example SMS_text : a pointer where SMS text will be placed max_SMS_len: maximum length of SMS text excluding also string terminating 0x00 character return: ERROR ret. val: --------------- -1 - comm. line to the GSM module is not free -2 - GSM module didn't answer in timeout -3 - specified position must be > 0 OK ret val: ----------- GETSMS_NO_SMS - no SMS was not found at the specified position GETSMS_UNREAD_SMS - new SMS was found at the specified position GETSMS_READ_SMS - already read SMS was found at the specified position GETSMS_OTHER_SMS - other type of SMS was found an example of usage: GSM gsm; char position; char phone_num[20]; // array for the phone number string char sms_text[100]; // array for the SMS text string position = gsm.IsSMSPresent(SMS_UNREAD); if (position) { // there is new SMS => read it gsm.GetSMS(position, phone_num, sms_text, 100); #ifdef DEBUG_PRINT gsm.DebugPrint("DEBUG SMS phone number: ", 0); gsm.DebugPrint(phone_num, 0); gsm.DebugPrint("\r\n SMS text: ", 0); gsm.DebugPrint(sms_text, 1); #endif } **********************************************************/ char SMSGSM::GetSMS(byte position, char *phone_number, char *SMS_text, byte max_SMS_len) { char ret_val = -1; char *p_char; char *p_char1; byte len; if (position == 0) return (-3); if (CLS_FREE != gsm.GetCommLineStatus()) return (ret_val); gsm.SetCommLineStatus(CLS_ATCMD); phone_number[0] = 0; // end of string for now ret_val = GETSMS_NO_SMS; // still no SMS //send "AT+CMGR=X" - where X = position gsm.SimpleWrite(F("AT+CMGR=")); gsm.SimpleWriteln((int)position); // 5000 msec. for initial comm tmout // 100 msec. for inter character tmout switch (gsm.WaitResp(5000, 100, "+CMGR")) { case RX_TMOUT_ERR: // response was not received in specific time ret_val = -2; break; case RX_FINISHED_STR_NOT_RECV: // OK was received => there is NO SMS stored in this position if(gsm.IsStringReceived("OK")) { // there is only response OK // => there is NO SMS ret_val = GETSMS_NO_SMS; } else if(gsm.IsStringReceived("ERROR")) { // error should not be here but for sure ret_val = GETSMS_NO_SMS; } break; case RX_FINISHED_STR_RECV: // find out what was received exactly //response for new SMS: //+CMGR: "REC UNREAD","+XXXXXXXXXXXX",,"02/03/18,09:54:28+40" //There is SMS textOK if(gsm.IsStringReceived("\"REC UNREAD\"")) { // get phone number of received SMS: parse phone number string // +XXXXXXXXXXXX // ------------------------------------------------------- ret_val = GETSMS_UNREAD_SMS; } //response for already read SMS = old SMS: //+CMGR: "REC READ","+XXXXXXXXXXXX",,"02/03/18,09:54:28+40" //There is SMS text else if(gsm.IsStringReceived("\"REC READ\"")) { // get phone number of received SMS // -------------------------------- ret_val = GETSMS_READ_SMS; } else { // other type like stored for sending.. ret_val = GETSMS_OTHER_SMS; } // extract phone number string // --------------------------- p_char = strchr((char *)(gsm.comm_buf),','); p_char1 = p_char+2; // we are on the first phone number character p_char = strchr((char *)(p_char1),'"'); if (p_char != NULL) { *p_char = 0; // end of string strcpy(phone_number, (char *)(p_char1)); } // get SMS text and copy this text to the SMS_text buffer // ------------------------------------------------------ p_char = strchr(p_char+1, 0x0a); // find if (p_char != NULL) { // next character after is the first SMS character p_char++; // now we are on the first SMS character // find as the end of SMS string p_char1 = strchr((char *)(p_char), 0x0d); if (p_char1 != NULL) { // finish the SMS text string // because string must be finished for right behaviour // of next strcpy() function *p_char1 = 0; } // in case there is not finish sequence because the SMS is // too long (more then 130 characters) sms text is finished by the 0x00 // directly in the gsm.WaitResp() routine // find out length of the SMS (excluding 0x00 termination character) len = strlen(p_char); if (len < max_SMS_len) { // buffer SMS_text has enough place for copying all SMS text // so copy whole SMS text // from the beginning of the text(=p_char position) // to the end of the string(= p_char1 position) strcpy(SMS_text, (char *)(p_char)); } else { // buffer SMS_text doesn't have enough place for copying all SMS text // so cut SMS text to the (max_SMS_len-1) // (max_SMS_len-1) because we need 1 position for the 0x00 as finish // string character memcpy(SMS_text, (char *)(p_char), (max_SMS_len-1)); SMS_text[max_SMS_len] = 0; // finish string } } break; } gsm.SetCommLineStatus(CLS_FREE); return (ret_val); } /********************************************************** Method reads SMS from specified memory(SIM) position and makes authorization - it means SMS phone number is compared with specified SIM phonebook position(s) and in case numbers match GETSMS_AUTH_SMS is returned, otherwise GETSMS_NOT_AUTH_SMS is returned position: SMS position to be read <1..20> phone_number: a pointer where the tel. number string of received SMS will be placed so the space for the phone number string must be reserved - see example SMS_text : a pointer where SMS text will be placed max_SMS_len: maximum length of SMS text excluding terminating 0x00 character first_authorized_pos: initial SIM phonebook position where the authorization process starts last_authorized_pos: last SIM phonebook position where the authorization process finishes Note(important): ================ In case first_authorized_pos=0 and also last_authorized_pos=0 the received SMS phone number is NOT authorized at all, so every SMS is considered as authorized (GETSMS_AUTH_SMS is returned) return: ERROR ret. val: --------------- -1 - comm. line to the GSM module is not free -2 - GSM module didn't answer in timeout -3 - position must be > 0 OK ret val: ----------- GETSMS_NO_SMS - no SMS was found at the specified position GETSMS_NOT_AUTH_SMS - NOT authorized SMS found at the specified position GETSMS_AUTH_SMS - authorized SMS found at the specified position an example of usage: GSM gsm; char phone_num[20]; // array for the phone number string char sms_text[100]; // array for the SMS text string // authorize SMS with SIM phonebook positions 1..3 if (GETSMS_AUTH_SMS == gsm.GetAuthorizedSMS(1, phone_num, sms_text, 100, 1, 3)) { // new authorized SMS was detected at the SMS position 1 #ifdef DEBUG_PRINT gsm.DebugPrint("DEBUG SMS phone number: ", 0); gsm.DebugPrint(phone_num, 0); gsm.DebugPrint("\r\n SMS text: ", 0); gsm.DebugPrint(sms_text, 1); #endif } // don't authorize SMS with SIM phonebook at all if (GETSMS_AUTH_SMS == gsm.GetAuthorizedSMS(1, phone_num, sms_text, 100, 0, 0)) { // new SMS was detected at the SMS position 1 // because authorization was not required // SMS is considered authorized #ifdef DEBUG_PRINT gsm.DebugPrint("DEBUG SMS phone number: ", 0); gsm.DebugPrint(phone_num, 0); gsm.DebugPrint("\r\n SMS text: ", 0); gsm.DebugPrint(sms_text, 1); #endif } **********************************************************/ char SMSGSM::GetAuthorizedSMS(byte position, char *phone_number, char *SMS_text, byte max_SMS_len, byte first_authorized_pos, byte last_authorized_pos) { char ret_val = -1; byte i; ret_val = GetSMS(position, phone_number, SMS_text, max_SMS_len); if (ret_val < 0) { // here is ERROR return code => finish // ----------------------------------- } else if (ret_val == GETSMS_NO_SMS) { // no SMS detected => finish // ------------------------- } else if (ret_val == GETSMS_READ_SMS) { // now SMS can has only READ attribute because we have already read // this SMS at least once by the previous function GetSMS() // // new READ SMS was detected on the specified SMS position => // make authorization now // --------------------------------------------------------- if ((first_authorized_pos == 0) && (last_authorized_pos == 0)) { // authorization is not required => it means authorization is OK // ------------------------------------------------------------- ret_val = GETSMS_AUTH_SMS; } else { ret_val = GETSMS_NOT_AUTH_SMS; // authorization not valid yet for (i = first_authorized_pos; i <= last_authorized_pos; i++) { if (gsm.ComparePhoneNumber(i, phone_number)) { // phone numbers are identical // authorization is OK // --------------------------- ret_val = GETSMS_AUTH_SMS; break; // and finish authorization } } } } return (ret_val); } /********************************************************** Method deletes SMS from the specified SMS position position: SMS position <1..20> return: ERROR ret. val: --------------- -1 - comm. line to the GSM module is not free -2 - GSM module didn't answer in timeout -3 - position must be > 0 OK ret val: ----------- 0 - SMS was not deleted 1 - SMS was deleted **********************************************************/ char SMSGSM::DeleteSMS(byte position) { char ret_val = -1; if (position == 0) return (-3); if (CLS_FREE != gsm.GetCommLineStatus()) return (ret_val); gsm.SetCommLineStatus(CLS_ATCMD); ret_val = 0; // not deleted yet //send "AT+CMGD=XY" - where XY = position gsm.SimpleWrite(F("AT+CMGD=")); gsm.SimpleWriteln((int)position); // 5000 msec. for initial comm tmout // 20 msec. for inter character timeout switch (gsm.WaitResp(5000, 50, "OK")) { case RX_TMOUT_ERR: // response was not received in specific time ret_val = -2; break; case RX_FINISHED_STR_RECV: // OK was received => SMS deleted ret_val = 1; break; case RX_FINISHED_STR_NOT_RECV: // other response: e.g. ERROR => SMS was not deleted ret_val = 0; break; } gsm.SetCommLineStatus(CLS_FREE); return (ret_val); }