In a recent Arduino embedded system I needed to manage an Arduino GSM Shield for some specific use cases. However, I couldn’t use the well-known GSM library due to memory capacity limitations since this library “eats” the Arduino board memory 🙂 I could use an Arduino board with more memory capacity but this was not the case for me. I wrote the library SimpleGSM, which is a simple GSM library for managing the Arduino GSM shield (maybe you can use the library with other GSM cards) and execute some basic operations. I wrote the library to have exactly the operations I wanted. The library uses internally a software serial for the communication.

So, below is the source code of the SimpleGSM library.

SimpleGsm.h

#ifndef _SimpleGsm_H
#define _SimpleGsm_H

#include "Arduino.h"

#include <SoftwareSerial.h>

class SimpleGsm : public SoftwareSerial
{
  public:
    SimpleGsm (const byte rxPin, const byte txPin, const byte powerPin);

    bool begin (const long baudRate, const byte numberOfRetries);

    bool disableEcho ();

    bool setSmsTextMode ();

    bool sendSms (const String phoneNumber, const String message);

    bool missedCall (const String phoneNumber,
                     const unsigned long ringingDuration);

    bool startCall (const String phoneNumber);

    bool callIsDialing ();

    bool callIsRinging ();

    void waitOnCallDialing ();

    void waitOnCallRinging (const unsigned long duration);

    bool hangCall ();

  private:
    void restart ();

    bool setEcho (const bool state);

    bool setSmsMode (const byte mode);

    void queryForCallStatus ();

    bool responseIsReceived (char * const pattern, const long timeOut);

    static char * const OK_RESPONSE_FORMAT;

    byte _powerPin;
};

#endif /* _SimpleGsm_H */

SimpleGsm.cpp

#include "SimpleGsm.h"

char * const SimpleGsm::OK_RESPONSE_FORMAT = "\r\nOK\r\n";

SimpleGsm::SimpleGsm (const byte rxPin,
                      const byte txPin,
                      const byte powerPin) : SoftwareSerial (rxPin, txPin)
{
  _powerPin = powerPin;

  pinMode(_powerPin, OUTPUT);
}

void
SimpleGsm::restart ()
{
  digitalWrite(_powerPin, HIGH);

  delay(12000);

  digitalWrite(_powerPin, LOW);

  delay(1000);
}

bool
SimpleGsm::responseIsReceived (char * const pattern, const long timeOut)
{
  this->setTimeout(timeOut);

  return this->find(pattern);
}

bool
SimpleGsm::disableEcho ()
{
  return this->setEcho (false);
}

bool
SimpleGsm::setSmsTextMode ()
{
  return this->setSmsMode (1);
}

bool
SimpleGsm::setEcho (const bool state)
{
  this->print(F("ATE"));

  this->print(state);

  this->print(F("\r"));

  return this->responseIsReceived(OK_RESPONSE_FORMAT, 3000);
}

bool
SimpleGsm::setSmsMode (const byte mode)
{
  this->print(F("AT+CMGF="));

  this->print(mode);

  this->print(F("\r"));

  return this->responseIsReceived(OK_RESPONSE_FORMAT, 3000);
}

bool
SimpleGsm::begin (const long baudRate, const byte numberOfRetries)
{
  SoftwareSerial::begin (baudRate);

  for (byte i = 0; i < numberOfRetries; i++)
  {
    this->restart ();

    delay(1000);

    this->print(F("AT\r"));

    if (this->responseIsReceived(OK_RESPONSE_FORMAT, 3000))
    {
      return true;
    }
  }

  return false;
}

bool
SimpleGsm::sendSms (const String phoneNumber, const String message)
{
  this->print(F("AT+CMGS=\""));

  this->print(phoneNumber);

  this->print(F("\"\r"));

  if (!this->responseIsReceived("\r\n> ", 3000))
  {
    return false;
  }

  this->print(message);

  this->write(0x1A);

  return this->responseIsReceived(OK_RESPONSE_FORMAT, 10000);
}

bool
SimpleGsm::startCall (const String phoneNumber)
{
  this->print(F("ATD"));

  this->print(phoneNumber);

  this->print(F(";\r"));

  return this->responseIsReceived(OK_RESPONSE_FORMAT, 3000);
}

bool
SimpleGsm::callIsDialing()
{
  this->queryForCallStatus();

  return this->responseIsReceived("+CLCC: 1,0,2,0,0", 500);
}

bool
SimpleGsm::callIsRinging()
{
  this->queryForCallStatus();

  return this->responseIsReceived("+CLCC: 1,0,3,0,0", 500);
}

void
SimpleGsm::waitOnCallDialing()
{
  while (this->callIsDialing()) ;
}

void
SimpleGsm::waitOnCallRinging(const unsigned long duration)
{
  const unsigned long previousMillis = millis();

  while ((unsigned long) (millis() - previousMillis) < duration)
  {
    if (!this->callIsRinging())
    {
      break;
    }
  }
}

bool
SimpleGsm::missedCall (const String phoneNumber,
                       const unsigned long ringingDuration)
{
  if (this->startCall(phoneNumber))
  {
    this->waitOnCallDialing();

    if (this->callIsRinging())
    {
      this->waitOnCallRinging(ringingDuration);
    }

    this->hangCall();

    return true;
  }

  return false;
}

void
SimpleGsm::queryForCallStatus()
{
  this->print(F("AT+CLCC\r"));
}

bool
SimpleGsm::hangCall ()
{
  this->print(F("ATH\r"));

  return this->responseIsReceived(OK_RESPONSE_FORMAT, 3000);
}

Happy Hacking!