NOTE: To learn AVR Microcontrollers and do hands on experiments at home you can purchase xBoard. It is a low cost development board designed to get started with minimum efforts and to easily perform common tasks. Lots of sample programs helps you easily complete projects. It is a must have tool if you want to do something real and instead of just wasting time just trying to achieve basic things and avoid problems that dont let you move forward to the real task.
Buy xBoard NOW !
Free shipping across India ! Pay Cash on Delivery ! 15 Days Money Back!

Hi friends in this part we will have a look at the functions related to text messages. By the end of this article you will have a clear idea of how to wait for a text message, read the message, send a new text message and deleted a received message. We have already discussed the basics of SIM300 GSM Module interface with AVR MCU in our previous tutorial you can refer that article to know about the schematic and basic communication code.

After reading the above article you will know how we have connected the SIM300, AVR ATmega32 and LCD Module to make a basic test rig. Also covered in the article is the detail about the communication method between SIM300 and AVR which is called asynchronous serial communication, done using AVR’s USART peripheral. The article shows you how to use the AVR USART library to send and receive data to/from the GSM Module. We have also discussed the command response method used for the interfacing with the module. Working code is provided that shows you how to implement the command response based communication over USART with the SIM300 GSM Module. Those techniques are used through out this article so we recommend you to go through the article and do the demo project given there.

Waiting for a text message (SMS)

When a text message (SMS) arrives on SIM300 GSM Module it sends a unsolicited response <CR><LF>+CMTI: <mem>,<n><CR><LF>

I have already told in previous article that <CR> refers to a control character whose ASCII is 0D (Hex) and <LF> with ASCII code of 0A(Hex). The new thing you will learn about is unsolicited response. Earlier I told commands are followed by response. But the response discussed above is not followed by any command, it can come at any moment. So it is called an unsolicited response.

value of mem is the storage location where the sms was stored. Usually its value is SM, which stands for SIM memory.

the value of n is the sms slot on which the incoming message was stored. Depending on the size of storage in your SIM card their may me 20 or so slots in your card. When a message is received it is stored in the lowest numbered empty slot. For example you first received 4 messages then deleted the 1st message, then 5th message will get stored in slot 1.

Code Example showing how Wait for a message.


int8_t   SIM300WaitForMsg(uint8_t *id)
{
   //Wait for a unsolicited response for 250ms  
   uint8_t len=SIM300WaitForResponse(250);

   if(len==0)
      return SIM300_TIMEOUT;

   sim300_buffer[len-1]='\0';

   //Check if the response is +CMTI (Incoming msg indicator)
   if(strncasecmp(sim300_buffer+2,"+CMTI:",6)==0)
   {
      char str_id[4];

      char *start;

      start=strchr(sim300_buffer,',');
      start++;

      strcpy(str_id,start);

      *id=atoi(str_id);

      return SIM300_OK;
   }
   else
      return SIM300_FAIL;
}

Code Walkthrough

  1. We wait for a response from SIM300 with a time-out of 250 millisecond. That means if nothing comes for 250 millisecond we give up!
  2. If we get a response, SIM300WaitForResponse() returns its length till trailing <CR>. So suppose we got <CR><LF>+CMTI: SM,1<CR><LF> then len will be 14.
  3. Next line sim300_buffer[len-1]='\0'; puts an NULL character at position len – 1 that is 13(points to last <CR>). So the response actually becomes <CR><LF>+CMTI: SM,1
  4. Now we want to check if the first 6 characters are +CMTI: or not, we check first 6 characters only because the <n> following +CMTI is variable. Remember it is the slot number where the message is stored! Also while comparing we want to ignore the case, that means +CMTI or +cMtI are same. This type of string comparison is easily done using the standard C library function strncasecmp(). Well if you have ever attended a C training session in school you must have remembered strcmp() , so you can look strncasecmp().So you can see only an n and case is added in the name of the function. n in the name indicate you don’t have to compare the whole string, you can check the first n characters. While the case in the name indicate a case in-sensitive match. Also you notice we don’t pass sim300_buffer (which holds the response) directly to the comparison function, but we pass sim300_buffer + 2, this removes the leading <CR><LF> in the response string.
  5. If the response matches the next step is to extract the value of <n>, i.e. the message slot id. As you can see the slot id is after the first comma(,) in the response. So we search for the position of first comma in the response. This is done using strchr() standard library function. Now start points to a string which is ",1".
  6. The we do start++, this makes start points to a string which is "1", but remember it is still a string. So we use standard library function atoi() which converts a string to a integer. Which we store in *id. Remember the parameter id is pass by reference type, if you don’t know what does that means go and revise your C book!
  7. Finally we return SIM300_OK which is a constant defined in sim300.h indicating a success to caller.

Reading the Content of Text Message

The command that is used to read a text message from any slot is AT+CMGR=<n> where <n> is an integer value indicating the sms slot to read. As I have already discussed that their are several slots to hold incoming messages.

The response is like this

+CMGR: "STATUS","OA",,"SCTS"<CR><LF>Message Body<CR><LF><CR><LF>OK<CR><LF>

where STATUS indicate the status of message it could be REC UNREAD or REC READ

OA is the Originating Address that means the mobile number of the sender.

SCTS is the Service Center Time Stamp.

This is a simple example so we discard the first line data i.e. STATUS, OA and SCTS. We only read the Message Body.

One of the most interesting thing to note is that three things can happen while attempting to read a message ! They are listed below.

  1. Successful read in that case the response is like that discussed above.
  2. Empty slot ! That means an attempt has been make to read a slot that does not have any message stored in it. In this case the response is <CR><LF>OK<CR><LF>
  3. SIM card not ready! In this case +CMS ERROR: 517 is returned.

Our function handles all the three situations.


int8_t   SIM300ReadMsg(uint8_t i, char *msg)
{
   //Clear pending data in queue
   UFlushBuffer();

   //String for storing the command to be sent
   char cmd[16];

   //Build command string
   sprintf(cmd,"AT+CMGR=%d",i);

   //Send Command
   SIM300Cmd(cmd);

   uint8_t len=SIM300WaitForResponse(1000);

   if(len==0)
      return SIM300_TIMEOUT;

   sim300_buffer[len-1]='\0';

   //Check of SIM NOT Ready error
   if(strcasecmp(sim300_buffer+2,"+CMS ERROR: 517")==0)
   {
      //SIM NOT Ready
      return SIM300_SIM_NOT_READY;
   }

   //MSG Slot Empty
   if(strcasecmp(sim300_buffer+2,"OK")==0)
   {
      return SIM300_MSG_EMPTY;
   }

   //Now read the actual msg text
   len=SIM300WaitForResponse(1000);

   if(len==0)
      return SIM300_TIMEOUT;

   sim300_buffer[len-1]='\0';
   strcpy(msg,sim300_buffer+1);//+1 for removing trailing LF of prev line

   return SIM300_OK;
}

Code Walkthrough

  1. Clear pending data in the buffer.
  2. A command string is built using the standard library function sprintf().
    1. sprintf(cmd,"AT+CMGR=%d",i);
    2. You must be knowing that the above code gives a string in which placeholder %d is replaced by the value of i.
  3. Command is sent to the SIM300 module.
  4. Then we wait for the response.
  5. Response is analyzed.
  6. Finally messages is read and copied to the memory address pointed by *msg using standard library function strcpy().

Sending a New Text Message

We will develop a function to easily send message to any mobile number. This function has the argument

  • num (IN) – Phone number where to send the message ex "+919939XXXXXX"
  • msg (IN) – Message Body ex "This a message body"
  • msg_ref (OUT) – After successful send, the function stores a unique message reference in this variable.

The function returns an integer value indicating the result of operation which may be

  • SIM300_TIMEOUT – When their is some problem in communication line or the GSM module is not responding or switched off.
  • SIM300_FAIL – Message Sending Failed. A possible reason may be not enough balance in your prepaid account !
  • SIM300_OK – Message Send Success!

int8_t   SIM300SendMsg(const char *num, const char *msg,uint8_t *msg_ref)
{
   UFlushBuffer();

   char cmd[25];

   sprintf(cmd,"AT+CMGS= %s",num);

   cmd[8]=0x22; //"

   uint8_t n=strlen(cmd);

   cmd[n]=0x22; //"
   cmd[n+1]='\0';

   //Send Command
   SIM300Cmd(cmd);

   _delay_ms(100);

   UWriteString(msg);

   UWriteData(0x1A);
	
	//Wait for echo
   while(   UDataAvailable()<(strlen(msg)+5)   );

   //Remove Echo
   UReadBuffer(sim300_buffer,strlen(msg)+5);

   uint8_t len=SIM300WaitForResponse(6000);

   if(len==0)
      return SIM300_TIMEOUT;

   sim300_buffer[len-1]='\0';

   if(strncasecmp(sim300_buffer+2,"CMGS:",5)==0)
   {

      *msg_ref=atoi(sim300_buffer+8);

      UFlushBuffer();

      return SIM300_OK;
   }
   else
   {
      UFlushBuffer();
      return SIM300_FAIL;
   }
}

Code Walkthrough

  1. The beginning of the function implementation is similar to those done above, first we flush the buffer and build command string. Command string must be like this :-
    • AT+CMGS=<DA>, Where DA is the destination address i.e. the mobile number like AT+CMGS="+919939XXXXXX"
    • This function sprintf(cmd,"AT+CMGS= %s",num); gives a string like this AT+CMGS= +919939XXXXXX
    • cmd[8]=0x22; //" this like replaces the space just before +91 with " so we have a string like this AT+CMGS="+919939XXXXXX
    • cmd[n]=0x22; //" this adds a " in the end also so the string becomes AT+CMGS="+919939XXXXXX", but caution it removes the '\0' the null character that must be present to mark the end of string in C. So the following statement adds a NULL character at the end.
    • cmd[n+1]='\0';
  2. Then we send the command string prepared above.\
  3. We now write the message body to SIM300 module using the function UWriteString(msg);
  4. UWriteData(0x1A);Is used to send the control character called EOF (End of File) to mark the end of message.
  5. Since SIM300 echoes back everything we write to it, so we remove the echo by reading the data from the buffer.
  6. Finally we wait for the response, read the response and compare it to find out whether we succeeded or not.

Deleting a Text Message

This function takes an integer input which should be slot number of the message you wish to delete. Function may return the following values.

  • SIM300_TIMEOUT – When their is some problem in communication line or the GSM module is not responding or switched off.
  • SIM300_FAIL – Message Deleting Failed. A possible reason may be an incorrect slot number id.
  • SIM300_OK – Message Delete Success!

AT command of deleting a message is AT+CMGD=<n> where n is an slot of number of message you wish to delete. If delete is successful it returns OK. The function implementation is very simple compared to above functions. The steps are similar, that involves building a command string, sending command, waiting for response and verifying response.


int8_t   SIM300DeleteMsg(uint8_t i)
{
   UFlushBuffer();

   //String for storing the command to be sent
   char cmd[16];

   //Build command string
   sprintf(cmd,"AT+CMGD=%d",i);

   //Send Command
   SIM300Cmd(cmd);

   uint8_t len=SIM300WaitForResponse(1000);

   if(len==0)
      return SIM300_TIMEOUT;

   sim300_buffer[len-1]='\0';

   //Check if the response is OK
   if(strcasecmp(sim300_buffer+2,"OK")==0)
      return SIM300_OK;
   else
      return SIM300_FAIL;
}

SIM300 Message Send Receive Demo

To show all the above functions in working demo we have developed a small program. This program does all the basic routine task on boot up, that include the following :-

  • Initialize the LCD Module and the SIM300 GSM Module.
  • Print IMEI, Manufacturer name and model name.
  • Then it checks SIM card presence and connects to network.
  • When network connection succeeds its show name of the network. Eg. Airtel or Vodafone etc.
  • Finally it sends a message with message body "Test".
  • Then it waits for a message, when a message arrives reads it and displays on LCD.
  • Then the message is deleted.

/******************************************************************************

A basic demo program showing sms functions.

                                     NOTICE
                           --------
NO PART OF THIS WORK CAN BE COPIED, DISTRIBUTED OR PUBLISHED WITHOUT A
WRITTEN PERMISSION FROM EXTREME ELECTRONICS INDIA. THE LIBRARY, NOR ANY PART
OF IT CAN BE USED IN COMMERCIAL APPLICATIONS. IT IS INTENDED TO BE USED FOR
HOBBY, LEARNING AND EDUCATIONAL PURPOSE ONLY. IF YOU WANT TO USE THEM IN 
COMMERCIAL APPLICATION PLEASE WRITE TO THE AUTHOR.


WRITTEN BY:
AVINASH GUPTA
me@avinashgupta.com

*******************************************************************************/


#include <avr/io.h>
#include <util/delay.h>

#include "lib/lcd/lcd.h"
#include "lib/sim300/sim300.h"


void Halt();
int main(void)
{
   //Initialize LCD Module
   LCDInit(LS_NONE);

   //Intro Message
   LCDWriteString("SIM300 Demo !");
   LCDWriteStringXY(0,1,"By Avinash Gupta");

   _delay_ms(1000);

   LCDClear();


   //Initialize SIM300 module
   LCDWriteString("Initializing ...");
   int8_t r= SIM300Init();

   _delay_ms(1000);

   //Check the status of initialization
   switch(r)
   {
      case SIM300_OK:
         LCDWriteStringXY(0,1,"OK !");
         break;
      case SIM300_TIMEOUT:
         LCDWriteStringXY(0,1,"No response");
         Halt();
      case SIM300_INVALID_RESPONSE:
         LCDWriteStringXY(0,1,"Inv response");
         Halt();
      case SIM300_FAIL:
         LCDWriteStringXY(0,1,"Fail");
         Halt();
      default:
         LCDWriteStringXY(0,1,"Unknown Error");
         Halt();
   }

   _delay_ms(1000);

   //IMEI No display
   LCDClear();

   char imei[16];

   r=SIM300GetIMEI(imei);

   if(r==SIM300_TIMEOUT)
   {
      LCDWriteString("Comm Error !");
      Halt();
   }

   LCDWriteString("Device IMEI:");
   LCDWriteStringXY(0,1,imei);

   _delay_ms(1000);

   //Manufacturer ID
   LCDClear();

   char man_id[48];

   r=SIM300GetManufacturer(man_id);

   if(r==SIM300_TIMEOUT)
   {
      LCDWriteString("Comm Error !");
      Halt();
   }

   LCDWriteString("Manufacturer:");
   LCDWriteStringXY(0,1,man_id);

   _delay_ms(1000);

   //Manufacturer ID
   LCDClear();

   char model[48];

   r=SIM300GetModel(model);

   if(r==SIM300_TIMEOUT)
   {
      LCDWriteString("Comm Error !");
      Halt();
   }

   LCDWriteString("Model:");
   LCDWriteStringXY(0,1,model);

   _delay_ms(1000);



   //Check Sim Card Presence
   LCDClear();
   LCDWriteString("Checking SIMCard");

   _delay_ms(1000);

   r=SIM300IsSIMInserted();

   if (r==SIM300_SIM_NOT_PRESENT)
   {
      //Sim card is NOT present
      LCDWriteStringXY(0,1,"No SIM Card !");

      Halt();
   }
   else if(r==SIM300_TIMEOUT)
   {
      //Communication Error
      LCDWriteStringXY(0,1,"Comm Error !");

      Halt();
   }
   else if(r==SIM300_SIM_PRESENT)
   {
      //Sim card present
      LCDWriteStringXY(0,1,"SIM Card Present");

      _delay_ms(1000);
   }

   //Network search
   LCDClear();
   LCDWriteStringXY(0,0,"SearchingNetwork");

   uint8_t     nw_found=0;
   uint16_t tries=0;
   uint8_t     x=0;

   while(!nw_found)
   {
      r=SIM300GetNetStat();

      if(r==SIM300_NW_SEARCHING)
      {
         LCDWriteStringXY(0,1,"%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0");
         LCDWriteStringXY(x,1,"%1");
         LCDGotoXY(17,1);

         x++;

         if(x==16) x=0;

         _delay_ms(50);

         tries++;

         if(tries==600)
            break;
      }
      else
         break;

   }
   LCDClear();

   if(r==SIM300_NW_REGISTERED_HOME)
   {
      LCDWriteString("Network Found");
   }
   else
   {
      LCDWriteString("Cant Connt to NW!");
      Halt();
   }

   _delay_ms(1000);

   LCDClear();

   //Show Provider Name
   char pname[32];
   r=SIM300GetProviderName(pname);

   if(r==0)
   {
      LCDWriteString("Comm Error !");
      Halt();
   }

   LCDWriteString(pname);

   _delay_ms(1000);

   //Send MSG
   LCDClear();
   LCDWriteString("Sending Msg");

   uint8_t ref;


   r=SIM300SendMsg("+919939XXXXXX","Test",&ref);//Change phone number to some valid value!

   if(r==SIM300_OK)
   {
      LCDWriteStringXY(0,1,"Success");
      LCDWriteIntXY(9,1,ref,3);
   }
   else if(r==SIM300_TIMEOUT)
   {
      LCDWriteStringXY(0,1,"Time out !");
   }
   else
   {
      LCDWriteStringXY(0,1,"Fail  !");
   }

   _delay_ms(2000);

   //Wait for MSG
   uint8_t id;

   UFlushBuffer();

   while(1)
   {
      LCDClear();

      LCDWriteStringXY(0,0,"Waiting for msg");

      x=0;
      int8_t vx=1;

      while(SIM300WaitForMsg(&id)!=SIM300_OK)
      {
         LCDWriteStringXY(0,1,"%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0%0");
         LCDWriteStringXY(x,1,"%1");
         LCDGotoXY(17,1);

         x+=vx;

         if(x==15 || x==0) vx=vx*-1;
      }

      LCDWriteStringXY(0,1,"MSG Received    ");

      _delay_ms(1000);

      //Now read and display msg
      LCDClear();
      char msg[300];

      r=SIM300ReadMsg(id,msg);

      if(r==SIM300_OK)
      {

         LCDWriteStringXY(0,0,msg);

         _delay_ms(3000);

      }
      else
      {
         LCDWriteString("Err Reading Msg !");

         _delay_ms(3000);

      }

      //Finally delete the msg
      if (SIM300DeleteMsg(id)!=SIM300_OK)
      {
         LCDWriteString("Err Deleting Msg !");

         _delay_ms(3000);
      }

   }


   Halt();
}

void Halt()
{
   while(1);
}

Downloads

By

Avinash Gupta

Facebook,
Follow on Twitter.

www.AvinashGupta.com

me@avinashgupta.com