erdemarslan / GSMSim

GSM Library for SIMCOM Modules on Arduino.
MIT License
123 stars 55 forks source link

Proposing a new version of this class, compatible with other architectures where you find preexistent instances of HardwareSerial instead of SoftwareSerial #24

Closed JazzTp closed 4 years ago

JazzTp commented 4 years ago

Hi,

Here's an idea I hope you will like, to make this library also usable on other architectures where you don't have SoftwareSerial, you find preexistent instances of HardwareSerial instead.

NOTICE: The calls you are using to SoftwareSerial methods have equivalents of the same exact name in the HardwareSerial class, I didn't have to change any such calls. But I haven't checked that all methods actually behave the same way, I have only tested sending SMS messages so far [EDIT: and dialing a call to a landlilne or mobile phone, both things are working very fine now].

Very short story: I made a program on the STM32F103C8T6 board (very cheap yet much more capable than Uno/ProMini and Leonardo/ProMicro) which - apart other things - sends an SMS from a SIM800L GSM module.

Then, I wanted to give a look at your library and I liked it, you did a great job.

So, I spent a few hours seeing if it could be easily modified to work with a preexistent instance of HardwareSerial, instead of inheriting from SoftwareSerial.

I'm using the Roger Clark core for the STM32F103C8T6. In it, you find one pre-instantiated HardwareSerial object for each hardware serial interface on the board, there's no SoftwareSerial library available as far as I know (slash-dev's answer on this page corroborates that it would be nonsense to use SoftwareSerial on it).

Here's a quick mod of your example which sends an SMS + your GSMSim class. I started from the current official release ver 1.0.19. You don't have to take my work, apart for testing if you want, you can redo what I did rather quickly, starting from the next official GSMSim releaes which would integrate all current ongoing fixes/improvements.

In fact, the process was easy because you very diligently used "this->" every time you called a method inherited from SoftwareSerial.

So, the main modification is to define a member serialManager (or the name you like), which is a reference to an external preexistent instance of a HardwareSerial or SoftwareSerial object, and replace all occurrences of "this->" with "serialManager." occurrences.

Actually, I first modified it for HardwareSerial only and tested it, then I turned it into a template so the same source and maintanance/upgrade work would be usable with both HardwareSerial and SoftwareSerial classes (and possibly other method-to-method compatible classes).

IN CASE SOME PECULIAR PART OF THE SOURCE CODE WOULD HAVE TO BE DIFFERENT, THIS PAGE EXPLAINS HOW TO DO IT WITH "TEMPLATE SPECIALIZATION".

(Of course I had to touch a few other things, certain constructors become unnecessary because now you can initialize an external SerialSoftware object apart, before creating the GSMSim one, when you don't find a pre-instantiated HardwareSerial object of course, such as in the core I'm using with this STM32F103C8T6 boards.)

You'll see that I've also commented out the LED related lines, but you don't have to do the same of course.

I've seen on GitHub that a few minor problems have already been or are already being addressed, e.g. values which can't be represented with uint8_t, or lines with just "false" instead of "return false". The current version of the Arduino IDE was warning on them all.

Finally, I would advise to keep - as I was taught long ago - one single exit point from functions: instead of many return ... lines, you can have many lines like returnValue = ... and then one single return returnValue line at the end. But your source is so tidy that this is not a real issue.


Here's file GSMSim_TemplateSerialSMSv01.001.ino, quick mod of your SMS example:

#include <GSMSim_TemplateSerial.h>
/*  Orig lib GSMSim, let's see if we can also use it with a preexistent instance of HardwareSerial instead of inheriting from SoftwareSerial.
    Quick mod by Nicola "JazzTp" Bernardelli
    STM32F103C8T6 board with Roger Clark's core https://github.com/rogerclarkmelbourne/Arduino_STM32
    NOTICE: only tested sending SMS and dialing a number, so far.
*/

#ifdef BOARD_generic_stm32f103c
  #define DEFAULT_PIN_RESET PB0
#else
  #define DEFAULT_PIN_RESET 2
#endif

#define BAUD 9600

GSMSim_TemplateSerial<HardwareSerial> gsm(Serial2, DEFAULT_PIN_RESET);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  Serial.println("GSMSim_HWserial Library - SMS Example");
  Serial.println("");
  delay(1000);

  gsm.start(); // baud default 9600
  // gsm.start(BAUD);

  Serial.println("Changing to text mode.");
  gsm.smsTextMode(true); // TEXT or PDU mode. TEXT is readable :)

  const char* number = "+905123456789";
  char* message = "Hi my friend. How are you?"; // message lenght must be <= 160. Only english characters.

  Serial.println("Sending Message --->");
  Serial.println(gsm.smsSend(number, message)); // if success it returns true (1) else false (0)
  delay(2000);

  Serial.println("Listing unread message(s).");
  Serial.println(gsm.smsListUnread()); // if not unread messages have it returns "NO_SMS"

  Serial.println("Read SMS on index no = 1");
  Serial.println(gsm.smsRead(1)); // if no message in that index, it returns INDEX_NO_ERROR

}

void loop() {
  // put your main code here, to run repeatedly:
}

And here's file GSMSim_TemplateSerial.h quick mod of your class, you might simply call it GSMSim2 instead of GSMSim_TemplateSerial (it also contains what was in the .cpp file, but please see the note I left where that part begins).

Again: this class does not inherit from SoftwareSerial, this breaks compatibility, you would have to put all ongoing minor fixes into GSMSim, make one final official release, and then leave it and create the new GSMSim2 library, other developers did that with their libraries, leaving both the old and the new one available).

Please just let me know if you want me to e-mail you both files.

[EDIT: sorry I see that here some indent problems appear, I'm seeing it differently in GEdit.]

/*  Orig lib GSMSim, let's see if we can also use it with a preexistent instance of HardwareSerial instead of inheriting from SoftwareSerial.
    Quick mod by Nicola "JazzTp" Bernardelli
    STM32F103C8T6 board with Roger Clark's core https://github.com/rogerclarkmelbourne/Arduino_STM32
    NOTICE: only tested sending SMS and dialing a number, so far.
*/

/*
    GSMSim_TemplateSerial Library

    This library written for SIMCOM Sim800L module. Library may worked on any SIMCOM modules
    and GSM Shields.

    Created 11.05.2017
    By Erdem ARSLAN
    Modified 25.08.2017

    Erdem ARSLAN
    Science and Technology Teacher, an Arduino Lover =)
    erdemsaid@gmail.com
    https://www.erdemarslan.com/
    http://www.robothane.net/
    http://www.eralabs.net/

*/

#ifndef GSMSim_TemplateSerial_h
#define GSMSim_TemplateSerial_h
// #include <SoftwareSerial.h>
#include "Arduino.h"

// DEFAULT PIN DEFINATIONS IN HERE
// #define DEFAULT_RX_PIN 7
// #define DEFAULT_TX_PIN 8
// #define DEFAULT_RST_PIN 2

// #define DEFAULT_LED_FLAG true
// #define DEFAULT_LED_PIN 13
// #define DEFAULT_LED_PIN 32

#define DEFAULT_BAUD_RATE 9600
#define BUFFER_RESERVE_MEMORY   255
#define TIME_OUT_READ_SERIAL    5000

// PIN (PERSONAL IDENTIFICATION NUMBER) STATUS
#define PIN_READY 0
#define SIM_PIN 1
#define SIM_PUK 2
#define PH_SIM_PIN 3
#define PH_SIM_PUK 4
#define SIM_PIN2 5
#define SIM_PUK2 6
#define PIN_STATUS_UNKNOWN 7

// CALL STATUS
#define READY 0
#define UNKNOWN 2
#define RINGING 3
#define IN_CALL 4
#define NOT_READ 99

// CLASS BEGIN IN HERE
template <class HWorSW_Serial> class GSMSim_TemplateSerial /* : public SoftwareSerial nope, we want to be able to work with pre-instantiated objects */
{
    private:  /* consider changing to protected! */
    HWorSW_Serial& serialManager;

        uint32_t _baud;
        uint8_t _timeout;
        String _buffer;
        String _readSerial();
        String _readSerial(uint32_t timeout);

        uint8_t RESET_PIN;

    public:
    /*
        uint8_t RX_PIN;
        uint8_t TX_PIN;
        uint8_t RESET_PIN;
        uint8_t LED_PIN;
        bool    LED_FLAG;
        uint32_t BAUDRATE;
    */

        GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t _RESET_PIN);
    /*
        GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t _RESET_PIN, uint8_t rx, uint8_t tx);
        GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t _RESET_PIN, uint8_t rx, uint8_t tx, uint8_t rst);
        GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t _RESET_PIN, uint8_t rx, uint8_t tx, uint8_t rst, uint8_t led);
        GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t _RESET_PIN, uint8_t rx, uint8_t tx, uint8_t rst, uint8_t led, bool ledflag);
    */

        // Başlatıcı Fonksiyon
        void start();
        void start(uint32_t baud);
        // Reset Fonksiyonu
        void reset();

        // Kontrol Metotları

        // Telefon Fonksiyonunu ayarlar
        bool setPhoneFunc(uint8_t level);
        // Sinyal kalitesi
        uint8_t signalQuality();
        // Operatöre bağlı mı?
        bool isRegistered();
        // Sim kart takılımı
        bool isSimInserted();
        // pin durumu
        uint8_t pinStatus();
        // operatör adı
        String operatorName();
        // sim karttaki operatör adı
        String operatorNameFromSim();
        // telefon durumu
        uint8_t phoneStatus();
        // echo kapalı
        bool echoOff();
        // echo açıkı
        bool echoOn();
        // modül üreticisi
        String moduleManufacturer();
        // modül modeli
        String moduleModel();
        // modül revizyon
        String moduleRevision();
        // modül imei
        String moduleIMEI();
        // modül imei değiştirme
        bool moduleIMEIChange(const char* imeino);
        // modül sim no
        String moduleIMSI();
        // modül sim operatör no
        String moduleICCID();
        // zil volümü
        uint8_t ringerVolume();
        // zil seviyesini ayarlar
        bool setRingerVolume(uint8_t level);
        // speaker düzeyi
        uint8_t speakerVolume();
        // speaker düzeyini ayarla
        bool setSpeakerVolume(uint8_t level);
        // debug modu - verbose mode
        String moduleDebug();

        // Arama Fonksiyonları
        // arama yapar
        bool call(const char* phone_number);
        // arama cevaplar
        bool callAnswer();
        // aramayı sonlandırır
        bool callHangoff();
        // arama durumu
        uint8_t callStatus();
        // COLP u aktif veya pasif yapar
        bool callSetCOLP(bool active);
        // COLP aktif mi?
        bool callIsCOLPActive();
        // Arayanı söyleme aktif mi değil mi?
        bool callActivateListCurrent(bool active);
        // şimdi arayanı söyle
        String callReadCurrentCall(String serialRaw);

        // SMS Fonksiyonları
        // sms i text yada pdu moda döndürür
        bool smsTextMode(bool textModeON);
        // sms gönderir
        bool smsSend(const char* number, const char* message);
        // okunmamış mesaj listesi
        String smsListUnread();
        // indexi verilen mesajı oku
        String smsRead(uint8_t index);
        // indexi verilen mesajı oku
        String smsRead(uint8_t index, bool markRead);
        // serialden direk mesajı oku -> serialden gelen veri verilmeli
        String smsReadFromSerial(String serialRaw);
        // serialden gelen sms bilgisinin indexini ver
        uint8_t smsIndexFromSerial(String serialRaw);
        // mesaj merkezini öğren
        String smsReadMessageCenter();
        // mesaj merkezini değiştir
        bool smsChangeMessageCenter(const char* messageCenter);
        // mesajı sil
        bool smsDeleteOne(uint8_t index);
        // tüm okunmuşları sil
        bool smsDeleteAllRead();
        // tüm mesajları sil
        bool smsDeleteAll();

        // DTMF Fonksiyonları
        // DTMF yi ayarlar
        bool dtmfSet(bool active, uint8_t interval, bool reportTime, bool soundDetect);
        // DTMF yi serialden okur!
        String dtmfRead(String serialRaw);

        // USSD Kodları
        // USSD kodu gönderir
        bool ussdSend(const char* code);
        // Raw datadan cevabı okur!
        String ussdRead(String serialRaw);

        // Radyo Kodları
        bool fmOpen();
        bool fmOpen(bool mainChannel);
        bool fmOpen(bool mainChannel, int freq);
        bool fmIsOpened();
        bool fmClose();
        uint8_t fmGetFreq();
        bool fmSetFreq(int freq);
        uint8_t fmGetVolume();
        bool fmSetVolume(int volume);

        // GPRS Kodları
        // Connect to Bearer
        bool gprsConnectBearer();
        //String gprsConnectBearerT();
        bool gprsConnectBearer(String apn);
        bool gprsConnectBearer(String apn, String user, String password);

        // Check connection
        bool gprsIsConnected();
        // get ip address
        String gprsGetIP();
        // close gprs bearer connection
        bool gprsCloseConn();
        String gprsHTTPGet(String url);
        String gprsHTTPGet(String url, bool read);

        // NTP Komutları
        bool timeSetServer(int timezone);
        bool timeSetServer(int timezone, String server);
        String timeSyncFromServer();
        String timeGetRaw();
        void timeGet(int *day, int *month, int *year, int *hour, int *minute, int *second);

        // Email Komutları
        bool emailSMTPConf(String server, String port, bool useSSL);
        bool emailSMTPAuth(String username, String password);
        bool emailSMTPAuth(String username, String password, bool requireAuth);
        bool emailSMTPGmail(String username, String password);
        String emailSMTPWrite(String from, String to, String title, String message);
        String emailSMTPWrite(String from, String to, String title, String message, String fromName, String toName);
        String emailSMTPSend();

};

//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================
//==================================================================================

/* What follows was inside "GSMSim_TemplateSerial.cpp" before changing this class into a template.
   If you really want to keep it in a .cpp file, this web page mentions a few possibilities:
   https://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-a-h-file-and-imp
*/

/*
    GSMSim_TemplateSerial Library

    This library written for SIMCOM Sim800L module. Library may worked on any SIMCOM modules
    and GSM Shields.

    Created 11.05.2017
    By Erdem ARSLAN
    Modified 30.08.2017

    Erdem ARSLAN
    Science and Technology Teacher, an Arduino Lover =)
    erdemsaid@gmail.com
    https://www.erdemarslan.com/
    http://www.robothane.net/
    http://www.eralabs.net/

*/

#include "Arduino.h"
// #include "GSMSim_TemplateSerial.h"  the header includes this file

// #include <SoftwareSerial.h>

template <class HWorSW_Serial>
GSMSim_TemplateSerial<HWorSW_Serial>::GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t _RESET_PIN) /* : SoftwareSerial(DEFAULT_RX_PIN, DEFAULT_TX_PIN) */
  : serialManager(_serialManager), RESET_PIN(_RESET_PIN)
{
  /*
    RX_PIN = DEFAULT_RX_PIN;
    TX_PIN = DEFAULT_TX_PIN;
    RESET_PIN = DEFAULT_RST_PIN;
    LED_PIN = DEFAULT_LED_PIN;
    LED_FLAG = DEFAULT_LED_FLAG;
  */
}

/* ===================================================================

GSMSim_TemplateSerial<HWorSW_Serial>::GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t rx, uint8_t tx) /^ : SoftwareSerial(rx, tx) ^/
  : serialManager(_serialManager)
{
  /^
    RX_PIN = rx;
    TX_PIN = tx;
    RESET_PIN = DEFAULT_RST_PIN;
    LED_PIN = DEFAULT_LED_PIN;
    LED_FLAG = DEFAULT_LED_FLAG;
  ^/
}

GSMSim_TemplateSerial<HWorSW_Serial>::GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t rx, uint8_t tx, uint8_t rst) /^ : SoftwareSerial(rx, tx) ^/
  : serialManager(_serialManager)
{
  /^
    RX_PIN = rx;
    TX_PIN = tx;
    RESET_PIN = rst;
    LED_PIN = DEFAULT_LED_PIN;
    LED_FLAG = DEFAULT_LED_FLAG;
  ^/
}

GSMSim_TemplateSerial<HWorSW_Serial>::GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t rx, uint8_t tx, uint8_t rst, uint8_t led) /^ : SoftwareSerial(rx, tx) ^/
  : serialManager(_serialManager)
{
  /^
    RX_PIN = rx;
    TX_PIN = tx;
    RESET_PIN = rst;
    LED_PIN = led;
    LED_FLAG = DEFAULT_LED_FLAG;
  ^/
}

GSMSim_TemplateSerial<HWorSW_Serial>::GSMSim_TemplateSerial(HWorSW_Serial& _serialManager, uint8_t rx, uint8_t tx, uint8_t rst, uint8_t led, bool ledflag) /^ : SoftwareSerial(rx, tx) ^/
  : serialManager(_serialManager)
{
  /^
    RX_PIN = rx;
    TX_PIN = tx;
    RESET_PIN = rst;
    LED_PIN = led;
    LED_FLAG = ledflag;
  ^/
}
=================================================================== */

// Start GSMSim_TemplateSerial
template <class HWorSW_Serial>
void GSMSim_TemplateSerial<HWorSW_Serial>::start() {
    pinMode(RESET_PIN, OUTPUT);
    digitalWrite(RESET_PIN, HIGH);

    _baud = DEFAULT_BAUD_RATE;

    serialManager.begin(_baud);

  /*
    if (LED_FLAG) {
        pinMode(LED_PIN, OUTPUT);
    }
  */

    _buffer.reserve(BUFFER_RESERVE_MEMORY);
}

template <class HWorSW_Serial>
void GSMSim_TemplateSerial<HWorSW_Serial>::start(uint32_t baud) {
    pinMode(RESET_PIN, OUTPUT);
    digitalWrite(RESET_PIN, HIGH);

    _baud = baud;

    serialManager.begin(_baud);

  /*
    if (LED_FLAG) {
        pinMode(LED_PIN, OUTPUT);
    }
  */

    _buffer.reserve(BUFFER_RESERVE_MEMORY);
}

// Reset GMS Module
template <class HWorSW_Serial>
void GSMSim_TemplateSerial<HWorSW_Serial>::reset() {
  /*
    if (LED_FLAG) {
        digitalWrite(LED_PIN, HIGH);
    }
  */

    digitalWrite(RESET_PIN, LOW);
    delay(1000);
    digitalWrite(RESET_PIN, HIGH);
    delay(1000);

    // Modul kendine geldi mi onu bekle
    serialManager.print(F("AT\r"));
    while (_readSerial().indexOf("OK") == -1) {
        serialManager.print(F("AT\r"));
    }
  /*
    if (LED_FLAG) {
        digitalWrite(LED_PIN, LOW);
    }
  */
}

// SET PHONE FUNC
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::setPhoneFunc(uint8_t level = 1) {
    if(level != 0 || level != 1 || level != 4) {
        return false;
    }
    else {
        serialManager.print(F("AT+CFUN="));
        serialManager.print(String(level));
        serialManager.print(F("\r"));

        _buffer = _readSerial();
        if( (_buffer.indexOf("OK") ) != -1)  {
            return true;
        }
        else {
            return false;
        }
    }
}

// SIGNAL QUALTY - 0-31 | 0-> poor | 31 - Full | 99 -> Unknown
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::signalQuality() {
    serialManager.print(F("AT+CSQ\r"));
    _buffer = _readSerial();

    if((_buffer.indexOf("+CSQ:")) != -1) {
        return _buffer.substring(_buffer.indexOf("+CSQ: ")+6, _buffer.indexOf(",")).toInt();
    } else {
        return 99;
    }
}

// IS Module connected to the operator?
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::isRegistered() {
    serialManager.print(F("AT+CREG?\r"));
    _buffer = _readSerial();

    if( (_buffer.indexOf("+CREG: 0,1")) != -1 || (_buffer.indexOf("+CREG: 0,5")) != -1 || (_buffer.indexOf("+CREG: 1,1")) != -1 || (_buffer.indexOf("+CREG: 1,5")) != -1) {
        return true;
    } else {
        return false;
    }
}

// IS SIM Inserted?
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::isSimInserted() {
    serialManager.print(F("AT+CSMINS?\r"));
    _buffer = _readSerial();
    if(_buffer.indexOf(",") != -1) {
        // bölelim
        String veri = _buffer.substring(_buffer.indexOf(","), _buffer.indexOf("OK"));
        veri.trim();
        if(veri == "1") {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

// Pin statüsü - AT+CPIN?
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::pinStatus() {
    serialManager.print(F("AT+CPIN?\r"));
    _buffer = _readSerial();

    if(_buffer.indexOf("READY") != -1)
    {
        return 0;
    }
    else if(_buffer.indexOf("SIM PIN") != -1)
    {
        return 1;
    }
    else if(_buffer.indexOf("SIM PUK") != -1)
    {
        return 2;
    }
    else if(_buffer.indexOf("PH_SIM PIN") != -1)
    {
        return 3;
    }
    else if(_buffer.indexOf("PH_SIM PUK") != -1)
    {
        return 4;
    }
    else if(_buffer.indexOf("SIM PIN2") != -1)
    {
        return 5;
    }
    else if(_buffer.indexOf("SIM PUK2") != -1)
    {
        return 6;
    }
    else {
        return 7;
    }
}

// OPERATOR NAME
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::operatorName() {
    serialManager.print(F("AT+COPS?\r"));
    _buffer = _readSerial();

    if(_buffer.indexOf(",") == -1) {
        return "NOT CONNECTED";
    }
    else {
         return _buffer.substring(_buffer.indexOf(",\"")+2, _buffer.lastIndexOf("\""));
    }
}

// OPERATOR NAME FROM SIM
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::operatorNameFromSim() {
    serialManager.flush();
    serialManager.print(F("AT+CSPN?\r"));
    _buffer = _readSerial();
    delay(250);
    _buffer = _readSerial();
    /*
    return _buffer;
    */
    if(_buffer.indexOf("OK") != -1) {
        return _buffer.substring(_buffer.indexOf(" \"") + 2, _buffer.lastIndexOf("\""));
    }
    else {
        return "NOT CONNECTED";
    }

}

// PHONE STATUS
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::phoneStatus() {
    serialManager.print(F("AT+CPAS\r"));
    _buffer = _readSerial();

    if((_buffer.indexOf("+CPAS: ")) != -1)
    {
        return _buffer.substring(_buffer.indexOf("+CPAS: ")+7,_buffer.indexOf("+CPAS: ")+9).toInt();
    }
    else {
        return 99; // not read from module
    }
}

// ECHO OFF
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::echoOff() {
    serialManager.print(F("ATE0\r"));
    _buffer = _readSerial();
    if ( (_buffer.indexOf("OK") )!=-1 ) {
        return true;
   }
   else {
    return false;
   }
}

// ECHO ON
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::echoOn() {
    serialManager.print(F("ATE1\r"));
    _buffer = _readSerial();
    if ( (_buffer.indexOf("OK") )!=-1 ) {
        return true;
   }
   else {
    return false;
   }
}

// Modül Üreticisi
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleManufacturer() {
    serialManager.print(F("AT+CGMI\r"));
    _buffer = _readSerial();
    String veri = _buffer.substring(8, _buffer.indexOf("OK"));
    veri.trim();
    veri.replace("_", " ");
    return veri;
}

// Modül Modeli
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleModel() {
    serialManager.print(F("AT+CGMM\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(8, _buffer.indexOf("OK"));
    veri.trim();
    veri.replace("_", " ");
    return veri;
}

// Modül Revizyonu
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleRevision() {
    serialManager.print(F("AT+CGMR\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(_buffer.indexOf(":")+1 , _buffer.indexOf("OK"));
    veri.trim();
    return veri;
}

// Modülün IMEI numarası
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleIMEI() {
    serialManager.print(F("AT+CGSN\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(8, _buffer.indexOf("OK"));
    veri.trim();
    return veri;
}

// Modülün IMEI Numarasını değiştirir.
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::moduleIMEIChange(const char* imeino) {
    return true;
}

// Modülün SIM Numarası
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleIMSI() {
    serialManager.print(F("AT+CIMI\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(8, _buffer.indexOf("OK"));
    veri.trim();
    return veri;
}

// Sim Kart Seri Numarası
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleICCID() {
    serialManager.print(F("AT+CCID\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(8, _buffer.indexOf("OK"));
    veri.trim();

    return veri;
}

// Çalma Sesi
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::ringerVolume() {
    serialManager.print(F("AT+CRSL?\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(7, _buffer.indexOf("OK"));
    veri.trim();

    return veri.toInt();
}

// Çalma sesini ayarla
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::setRingerVolume(uint8_t level) {
    if(level > 100) {
        level = 100;
    }

    serialManager.print(F("AT+CRSL="));
    serialManager.print(level);
    serialManager.print(F("\r"));
    _buffer = _readSerial();

    if(_buffer.indexOf("OK") != -1) {
        return true;
    } else {
        return false;
    }
}

// Hoparlör sesi
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::speakerVolume() {
    serialManager.print(F("AT+CLVL?\r"));
    _buffer = _readSerial();

    String veri = _buffer.substring(7, _buffer.indexOf("OK"));
    veri.trim();

    return veri.toInt();
}

// Hoparlör sesini ayarla
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::setSpeakerVolume(uint8_t level) {
    if(level > 100) {
        level = 100;
    }

    serialManager.print(F("AT+CLVL="));
    serialManager.print(level);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::moduleDebug() {
    serialManager.print(F("AT&V\r"));

    return _readSerial();
}

//////////////////////////////////////
//          CALL    SECTION         //
//////////////////////////////////////

// Arama Yapar
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::call(const char* phone_number) {

    bool sorgulamaYapma = callIsCOLPActive();
    _buffer = _readSerial();
    delay(100);

    serialManager.print(F("ATD+ "));  /* ATDnumber; => NO DIALTONE, ATD+ works, for instance ATD+ +541198765432; seen here https://lastminuteengineers.com/sim800l-gsm-module-arduino-tutorial/ NOTICE that it is not mentioned in SIM800_Series_AT_Command_Manual_V1.09.pdf */
    serialManager.print(phone_number);
    serialManager.print(";\r");

    if (sorgulamaYapma) {
        return true;
    }
    else {
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1)
        {
            return true;
        }
        else {
            return false;
        }
    }
}

// Gelen aramayı cevaplar
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::callAnswer() {
    serialManager.print(F("ATA\r"));

    _buffer = _readSerial();

  return (_buffer.indexOf("OK") != -1);
  /*
    if (_buffer.indexOf("OK") != -1)
    {
        return true;
    }
    else {
        return false;
    }
  */
}

// Aramayı reddeder veya görüşmeyi sonlandırır!
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::callHangoff() {
    serialManager.print(F("ATH\r"));
    _buffer = _readSerial();

  return (_buffer.indexOf("OK") != -1);
  /*
    if (_buffer.indexOf("OK") != -1)
    {
        return true;
    } else {
        return false;
    }
  */
}

// Arama durumunu belirtir
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::callStatus() {
    /*
        values of return:
        0 Ready (MT allows commands from TA/TE)
        2 Unknown (MT is not guaranteed to respond to tructions)
        3 Ringing (MT is ready for commands from TA/TE, but the ringer is active)
        4 Call in progress
    */
    serialManager.print(F("AT+CPAS\r"));
    _buffer = _readSerial();
    return _buffer.substring(_buffer.indexOf("+CPAS: ") + 7, _buffer.indexOf("+CPAS: ") + 9).toInt();
}

// Connected Line Identification aktif veya kapalı
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::callSetCOLP(bool active) {
    int durum = active == true ? 1 : 0;
    serialManager.print(F("AT+COLP="));
    serialManager.print(durum);
    serialManager.print("\r");

    _buffer = _readSerial();

  return (_buffer.indexOf("OK") != -1);
}

// COLP Aktif mi değil mi?
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::callIsCOLPActive() {
    serialManager.print("AT+COLP?\r");
    _buffer = _readSerial();

    return (_buffer.indexOf("+COLP: 1") != -1);
}

// Arayanı söyleme aktif mi değil mi?
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::callActivateListCurrent(bool active) {
    int durum = active == true ? 1 : 0;
    serialManager.print(F("AT+CLCC="));
    serialManager.print(durum);
    serialManager.print("\r");

    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

// şimdi arayanı söyle
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::callReadCurrentCall(String serialRaw) {

    String sonuc = "";
    if (serialRaw.indexOf("+CLCC:") != -1) {
        String durum = serialRaw.substring(11,13);
        String numara = serialRaw.substring(18, serialRaw.indexOf("\","));

        if (durum == "0") {
            durum = "STATUS:ACTIVE"; // Görüşme var
        }
        else if (durum == "1") {
            durum = "STATUS:HELD";
        }
        else if (durum == "2") {
            durum = "STATUS:DIALING"; // Çevriliyor
        }
        else if (durum == "3") {
            durum = "STATUS:ALERTING"; // Çalıyor
        }
        else if (durum == "4") {
            durum = "STATUS:INCOMING"; // Gelen arama
        }
        else if (durum == "5") {
            durum = "STATUS:WAITING"; // gelen arama bekliyor
        }
        else if (durum == "6") {
            durum = "STATUS:DISCONNECT"; // görüşme bitti
        }

        sonuc = durum + "|NUMBER:" + numara;
    }

    return sonuc;
}

//////////////////////////////////////
//          MESAJ BÖLÜMÜ            //
//////////////////////////////////////

// SMS i TEXT ya da PDU moduna alır.
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::smsTextMode(bool textModeON) {
    if (textModeON == true) {
        serialManager.print(F("AT+CMGF=1\r"));
    }
    else {
        serialManager.print(F("AT+CMGF=0\r"));
    }
    bool sonuc = false;
    _buffer = _readSerial();
    if (_buffer.indexOf("OK") != -1) {
        sonuc = true;
    }

    return sonuc;
}

// verilen numara ve mesajı gönderir!
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::smsSend(const char* number, const char* message) {
    serialManager.print(F("AT+CMGS=\""));  // command to send sms
    serialManager.print(number);
    serialManager.print(F("\"\r"));
    _buffer = _readSerial();
    serialManager.print(message);
    serialManager.print("\r");
    //change delay 100 to readserial
    _buffer += _readSerial();
    serialManager.print((char)26);

    _buffer += _readSerial();
    //expect CMGS:xxx   , where xxx is a number,for the sending sms.
    /*
    return _buffer;
    */
    if (((_buffer.indexOf("AT+CMGS")) != -1)) {
        return true;
    }
    else {
        return false;
    }
}

// Belirtilen klasördeki smslerin indexlerini listeler!
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::smsListUnread() {

    serialManager.print(F("AT+CMGL=\"REC UNREAD\",1\r"));

    _buffer = _readSerial();

    String donus = "";

    if (_buffer.indexOf("ERROR") != -1) {
        donus = "ERROR";
    }

    if (_buffer.indexOf("+CMGL:") != -1) {

        String veri = _buffer;
        bool islem = false;
        donus = "";

        while (!islem) {
            if (veri.indexOf("+CMGL:") == -1) {
                islem = true;
                continue;
            }

            veri = veri.substring(veri.indexOf("+CMGL: ") + 7);
            String metin = veri.substring(0, veri.indexOf(","));
            metin.trim();

            if (donus == "") {
                donus += "SMSIndexNo:";
                donus += metin;
            }
            else {
                donus += ",";
                donus += metin;
            }

        }

    }
    else {
        if (donus != "ERROR") {
            donus = "NO_SMS";
        }
    }

    return donus;
}

// Indexi verilen mesajı okur. Anlaşılır hale getirir!
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::smsRead(uint8_t index) {
    serialManager.print("AT+CMGR=");
    serialManager.print(index);
    serialManager.print(",0\r");

    _buffer = _readSerial();

    String durum = "INDEX_NO_ERROR";

    if (_buffer.indexOf("+CMGR:") != -1) {

        String klasor, okundumu, telno, zaman, mesaj;

        klasor = "UNKNOWN";
        okundumu = "UNKNOWN";

        if (_buffer.indexOf("REC UNREAD") != -1) {
            klasor = "INCOMING";
            okundumu = "UNREAD";
        }
        if (_buffer.indexOf("REC READ") != -1) {
            klasor = "INCOMING";
            okundumu = "READ";
        }
        if (_buffer.indexOf("STO UNSENT") != -1) {
            klasor = "OUTGOING";
            okundumu = "UNSENT";
        }
        if (_buffer.indexOf("STO SENT") != -1) {
            klasor = "OUTGOING";
            okundumu = "SENT";
        }

        String telno_bol1 = _buffer.substring(_buffer.indexOf("\",\"") + 3);
        telno = telno_bol1.substring(0, telno_bol1.indexOf("\",\"")); // telefon numarası tamam

        String tarih_bol = telno_bol1.substring(telno_bol1.lastIndexOf("\",\"") + 3);

        zaman = tarih_bol.substring(0, tarih_bol.indexOf("\"")); // zamanı da aldık. Bir tek mesaj kaldı!

        mesaj = tarih_bol.substring(tarih_bol.indexOf("\"") + 1, tarih_bol.lastIndexOf("OK"));

        mesaj.trim();

        durum = "FOLDER:";
        durum += klasor;
        durum += "|STATUS:";
        durum += okundumu;
        durum += "|PHONENO:";
        durum += telno;
        durum += "|DATETIME:";
        durum += zaman;
        durum += "|MESSAGE:";
        durum += mesaj;
    }

    return durum;
}

// Indexi verilen mesajı okur. Anlaşılır hale getirir!
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::smsRead(uint8_t index, bool markRead) {
    serialManager.print("AT+CMGR=");
    serialManager.print(index);
    serialManager.print(",");
    if (markRead == true) {
        serialManager.print("0");
    }
    else {
        serialManager.print("1");
    }
    serialManager.print("\r");

    _buffer = _readSerial();

    String durum = "INDEX_NO_ERROR";

    if (_buffer.indexOf("+CMGR:") != -1) {

        String klasor, okundumu, telno, zaman, mesaj;

        klasor = "UNKNOWN";
        okundumu = "UNKNOWN";

        if (_buffer.indexOf("REC UNREAD") != -1) {
            klasor = "INCOMING";
            okundumu = "UNREAD";
        }
        if (_buffer.indexOf("REC READ") != -1) {
            klasor = "INCOMING";
            okundumu = "READ";
        }
        if (_buffer.indexOf("STO UNSENT") != -1) {
            klasor = "OUTGOING";
            okundumu = "UNSENT";
        }
        if (_buffer.indexOf("STO SENT") != -1) {
            klasor = "OUTGOING";
            okundumu = "SENT";
        }

        String telno_bol1 = _buffer.substring(_buffer.indexOf("\",\"") + 3);
        telno = telno_bol1.substring(0, telno_bol1.indexOf("\",\"")); // telefon numarası tamam

        String tarih_bol = telno_bol1.substring(telno_bol1.lastIndexOf("\",\"") + 3);

        zaman = tarih_bol.substring(0, tarih_bol.indexOf("\"")); // zamanı da aldık. Bir tek mesaj kaldı!

        mesaj = tarih_bol.substring(tarih_bol.indexOf("\"")+1, tarih_bol.lastIndexOf("OK"));

        mesaj.trim();

        durum = "FOLDER:";
        durum += klasor;
        durum += "|STATUS:";
        durum += okundumu;
        durum += "|PHONENO:";
        durum += telno;
        durum += "|DATETIME:";
        durum += zaman;
        durum += "|MESSAGE:";
        durum += mesaj;
    }

    return durum;
}

// Serialden Mesajı okur
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::smsReadFromSerial(String serialRaw) {
    if (serialRaw.indexOf("+CMTI:") != -1) {
        String numara = serialRaw.substring(serialRaw.indexOf("\",") + 2);
        int no = numara.toInt();

        return smsRead(no, true);
    }
    else {
        return "RAW_DATA_NOT_READ";
    }
}

// serialden mesajın indexini alır
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::smsIndexFromSerial(String serialRaw) {
    if (serialRaw.indexOf("+CMTI:") != -1) {
        String numara = serialRaw.substring(serialRaw.indexOf("\",") + 2);
        int no = numara.toInt();

        return no;
    }
    else {
        return -1;
    }
}

// mesaj merkez numasını getirir
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::smsReadMessageCenter() {
    serialManager.print("AT+CSCA?\r");
    _buffer = _readSerial();

    String sonuc = "";

    if (_buffer.indexOf("+CSCA:") != -1)
    {
        sonuc = _buffer.substring(_buffer.indexOf("+CSCA:")+8, _buffer.indexOf("\","));
    }

    return sonuc;
}

// mesaj merkez numarasını değiştirir
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::smsChangeMessageCenter(const char* messageCenter) {
    serialManager.print("AT+CSCA=\"");
    serialManager.print(messageCenter);
    serialManager.print("\"\r");

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

// tek bir mesajı siler
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::smsDeleteOne(uint8_t index) {
    serialManager.print(F("AT+CMGD="));
    serialManager.print(index);
    serialManager.print(F(",0\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }

}

// Tüm okunmuş mesajlaarı siler. Fakat gidene dokunmaz
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::smsDeleteAllRead() {
    serialManager.print(F("AT+CMGD=1,1\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

// okunmuş okunmamış ne varsa siler
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::smsDeleteAll() {
    serialManager.print(F("AT+CMGD=1,4\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

//////////////////////////////////////
//          DTMF BÖLÜMÜ             //
//////////////////////////////////////

// DTMF yi ayarlar
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::dtmfSet(bool active, uint8_t interval, bool reportTime, bool soundDetect) {
    int mode = active == true ? 1 : 0;
    int rtime = reportTime == true ? 1 : 0;
    int ssdet = soundDetect == true ? 1 : 0;

    serialManager.print(F("AT+DDET="));
    serialManager.print(mode);
    serialManager.print(F(","));
    serialManager.print(interval);
    serialManager.print(F(","));
    serialManager.print(rtime);
    serialManager.print(F(","));
    serialManager.print(ssdet);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

// Serialden DTMF Yi okur ve karakter olarak geri döner!
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::dtmfRead(String serialRaw) {

    if (serialRaw.indexOf("+DTMF:") != -1) {
        //  var mı yok mu?
        String metin;
        if (serialRaw.indexOf(",") != -1) {
            metin = serialRaw.substring(7, serialRaw.indexOf(","));
        }
        else {
            metin = serialRaw.substring(7);
        }

        return metin;
    }
    else {
        return "?";
    }

}

//////////////////////////////////////
//          USSD SECTION            //
//////////////////////////////////////
// USSD kodu gönderir
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::ussdSend(const char* code) {
    serialManager.print(F("AT+CUSD=1,\""));
    serialManager.print(code);
    serialManager.print(F("\"\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}
// Raw datadan cevabı okur!
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::ussdRead(String serialRaw) {
    if (serialRaw.indexOf("+CUSD:") != -1) {
        String metin = serialRaw.substring(serialRaw.indexOf(",\"") + 2, serialRaw.indexOf("\","));
        return metin;
    }
    else {
        return "NOT_USSD_RAW";
    }
}

//////////////////////////////////////
//          FM RADIO SECTION        //
//////////////////////////////////////

// SIM800L & SIM800H only

// FM RADIO Open
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmOpen() {
    serialManager.print(F("AT+FMOPEN=0\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmOpen(bool mainChannel) {
    uint8_t channel = mainChannel == true ? 1 : 0;
    serialManager.print(F("AT+FMOPEN="));
    serialManager.print(channel);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmOpen(bool mainChannel, int freq) {
    uint8_t channel = mainChannel == true ? 1 : 0;
  int frekans = 875;

    if (freq < 875) {
        frekans = 875;
    }
    else if (freq > 1080) {
        frekans = 1080;
    }

    serialManager.print(F("AT+FMOPEN="));
    serialManager.print(channel);
    serialManager.print(",");
    serialManager.print(frekans);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

// IS FM OPENED?
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmIsOpened() {
    serialManager.print(F("AT+FMOPEN?\r"));
    _buffer = _readSerial();

    return (_buffer.indexOf("+FMOPEN: 1") != -1);
}

// FM RADIO CLOSE
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmClose() {
    serialManager.print(F("AT+FMCLOSE\r"));
    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

// GET FM RADIO FREQ
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::fmGetFreq() {
    serialManager.print(F("AT+FMFREQ?\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("+FMFREQ:") != -1) {
        String sonuc = _buffer.substring(_buffer.indexOf("+FMFREQ:")+8);
        sonuc.trim();
        return sonuc.toInt();
    }
    else {
        return 0;
    }
}

// SET FM RADIO FREQ
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmSetFreq(int freq) {
    serialManager.print(F("AT+FMFREQ="));
    int frekans = 875;
    if (freq < 875) {
        frekans = 875;
    }
    if (freq > 1080) {
        frekans = 1080;
    }
    serialManager.print(frekans);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

// GET FM RADIO FREQ
template <class HWorSW_Serial>
uint8_t GSMSim_TemplateSerial<HWorSW_Serial>::fmGetVolume() {
    serialManager.print(F("AT+FMVOLUME?\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("+FMVOLUME:") != -1) {
        String sonuc = _buffer.substring(_buffer.indexOf("+FMVOLUME:")+10);
        sonuc.trim();
        return sonuc.toInt();
    }
    else {
        return 0;
    }
}

// SET FM RADIO FREQ
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::fmSetVolume(int volume) {
    serialManager.print(F("AT+FMVOLUME="));
    uint8_t vol = 0;
    if (volume < 0) {
        vol = 0;
    }
    if (volume > 6) {
        vol = 6;
    }
    serialManager.print(vol);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

//////////////////////////////////////
//          GPRS METHODS            //
//////////////////////////////////////
// Connect to GPRS Bearer

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::gprsConnectBearer() {
    serialManager.print(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {

        delay(100);
        serialManager.print(F("AT+SAPBR=3,1,\"APN\",\"internet\"\r"));
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1) {
            delay(100);

            serialManager.print(F("AT+SAPBR=3,1,\"USER\",\"\"\r"));
            _buffer = _readSerial();

            if (_buffer.indexOf("OK") != -1) {

                delay(100);

                serialManager.print(F("AT+SAPBR=3,1,\"PWD\",\"\"\r"));
                _buffer = _readSerial();

                if (_buffer.indexOf("OK") != -1) {

                    delay(100);
                    serialManager.print("AT+SAPBR=1,1\r");
                    _buffer = _readSerial();
                    delay(50);
                    _buffer += _readSerial();
                    if (_buffer.indexOf("OK") != -1) {

                        serialManager.print("AT+SAPBR=2,1\r");
                        _buffer = _readSerial();

                        if (_buffer.indexOf("\"0.0.0.0\"") != -1 || _buffer.indexOf("ERR") != -1) {
                            return false;
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                        return false;
                    }

                }
                else {
                    return false;
                }
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::gprsConnectBearer(String apn) {
    serialManager.print(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {

        delay(100);
        serialManager.print(F("AT+SAPBR=3,1,\"APN\",\""));
        serialManager.print(apn);
        serialManager.print(F("\"\r"));
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1) {
            delay(100);

            serialManager.print(F("AT+SAPBR=3,1,\"USER\",\"\"\r"));
            _buffer = _readSerial();

            if (_buffer.indexOf("OK") != -1) {

                delay(100);

                serialManager.print(F("AT+SAPBR=3,1,\"PWD\",\"\"\r"));
                _buffer = _readSerial();

                if (_buffer.indexOf("OK") != -1) {

                    delay(100);
                    serialManager.print("AT+SAPBR=1,1\r");
                    _buffer = _readSerial();
                    delay(50);
                    _buffer += _readSerial();
                    if (_buffer.indexOf("OK") != -1) {

                        serialManager.print("AT+SAPBR=2,1\r");
                        _buffer = _readSerial();

                        if (_buffer.indexOf("\"0.0.0.0\"") != -1 || _buffer.indexOf("ERR") != -1) {
                            return false;
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                        return false;
                    }

                }
                else {
                    return false;
                }
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::gprsConnectBearer(String apn, String user, String password) {
    serialManager.print(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {

        delay(100);
        serialManager.print(F("AT+SAPBR=3,1,\"APN\",\""));
        serialManager.print(apn);
        serialManager.print(F("\"\r"));
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1) {
            delay(100);

            serialManager.print(F("AT+SAPBR=3,1,\"USER\",\""));
            serialManager.print(user);
            serialManager.print(F("\"\r"));
            _buffer = _readSerial();

            if (_buffer.indexOf("OK") != -1) {

                delay(100);

                serialManager.print(F("AT+SAPBR=3,1,\"PWD\",\""));
                serialManager.print(password);
                serialManager.print(F("\"\r"));
                _buffer = _readSerial();

                if (_buffer.indexOf("OK") != -1) {

                    delay(100);
                    serialManager.print("AT+SAPBR=1,1\r");
                    _buffer = _readSerial();
                    delay(50);
                    _buffer += _readSerial();
                    if (_buffer.indexOf("OK") != -1) {

                        serialManager.print("AT+SAPBR=2,1\r");
                        _buffer = _readSerial();

                        if (_buffer.indexOf("\"0.0.0.0\"") != -1 || _buffer.indexOf("ERR") != -1) {
                            return false;
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                        return false;
                    }

                }
                else {
                    return false;
                }
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

// Check is GPRS connected?
template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::gprsIsConnected() {
    serialManager.print(F("AT+SAPBR=2,1\r"));
    _buffer = _readSerial();
    delay(50);
    _buffer += _readSerial();

    if (_buffer.indexOf("ERR") != -1 || _buffer.indexOf("\"0.0.0.0\"") != -1) {
        return false;
    }
    else {
        return true;
    }
}

// GET IP Address
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::gprsGetIP() {
    serialManager.print(F("AT+SAPBR=2,1\r\n"));
    _buffer = _readSerial();
    delay(50);
    _buffer += _readSerial();

    //return _buffer;

    if (_buffer.indexOf("ERR") != -1 || _buffer.indexOf("\"0.0.0.0\"") != -1) {
        return "ERROR:NO_IP";
    }
    else {
        if (_buffer.indexOf("+SAPBR:") != -1) {
            String veri = _buffer.substring(_buffer.indexOf(",\"")+2, _buffer.lastIndexOf("\""));
            veri.trim();
            return veri;
        }
        else {
            return "ERROR:NO_IP_FETCH";
        }
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::gprsCloseConn() {
    serialManager.print(F("AT+SAPBR=0,1\r"));
    _buffer = _readSerial();
    delay(50);
    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::gprsHTTPGet(String url) {
    if (gprsIsConnected()) {
        // Terminate http connection, if it opened before!
        serialManager.print(F("AT+HTTPTERM\r"));
        _buffer = _readSerial();

        serialManager.print(F("AT+HTTPINIT\r"));
        _buffer = _readSerial();
        if (_buffer.indexOf("OK") != -1) {
            serialManager.print(F("AT+HTTPPARA=\"CID\",1\r"));
            _buffer = _readSerial();
            if (_buffer.indexOf("OK") != -1) {
                serialManager.print(F("AT+HTTPPARA=\"URL\",\""));
                serialManager.print(url);
                serialManager.print("\"\r");
                _buffer = _readSerial();

                if (_buffer.indexOf("OK") != -1) {
                    serialManager.print(F("AT+HTTPACTION=0\r"));
                    _buffer = _readSerial();
                    if (_buffer.indexOf("OK") != -1) {
                        delay(100);
                        _buffer = _readSerial(10000);
                        if (_buffer.indexOf("+HTTPACTION: 0,") != -1) {
                            String kod = _buffer.substring(_buffer.indexOf(",")+1, _buffer.lastIndexOf(","));
                            String uzunluk = _buffer.substring(_buffer.lastIndexOf(",")+1);

                            String sonuc = "METHOD:GET|HTTPCODE:";
                            sonuc += kod;
                            sonuc += "|LENGTH:";
                            sonuc += uzunluk;

                            // Bağlantıyı kapat!
                            serialManager.print(F("AT+HTTPTERM\r"));
                            _buffer = _readSerial();

                            sonuc.trim();

                            return sonuc;
                        }
                        else {
                            return "HTTP_ACTION_READ_ERROR";
                        }
                    }
                    else {
                        return "HTTP_ACTION_ERROR";
                    }
                }
                else {
                    return "HTTP_PARAMETER_ERROR";
                }

            }
            else {
                return "HTTP_PARAMETER_ERROR";
            }
        }
        else {
            return "HTTP_INIT_ERROR";
        }
    }
    else {
        return "GPRS_NOT_CONNECTED";
    }
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::gprsHTTPGet(String url, bool read) {
    if (gprsIsConnected()) {
        // Terminate http connection, if it opened before!
        serialManager.print(F("AT+HTTPTERM\r"));
        _buffer = _readSerial();

        serialManager.print(F("AT+HTTPINIT\r\n"));
        _buffer = _readSerial();

        //return _buffer;
        if (_buffer.indexOf("OK") != -1) {
            serialManager.print(F("AT+HTTPPARA=\"CID\",1\r"));
            _buffer = _readSerial();
            if (_buffer.indexOf("OK") != -1) {
                serialManager.print(F("AT+HTTPPARA=\"URL\",\""));
                serialManager.print(url);
                serialManager.print(F("\"\r"));
                _buffer = _readSerial();

                if (_buffer.indexOf("OK") != -1) {
                    serialManager.print(F("AT+HTTPACTION=0\r"));
                    _buffer = _readSerial();
                    if (_buffer.indexOf("OK") != -1) {
                        delay(100);
                        _buffer = _readSerial(10000);
                        if (_buffer.indexOf("+HTTPACTION: 0,") != -1) {
                            String kod = _buffer.substring(_buffer.indexOf(",") + 1, _buffer.lastIndexOf(","));
                            String uzunluk = _buffer.substring(_buffer.lastIndexOf(",") + 1);
                            kod.trim();
                            uzunluk.trim();

                            serialManager.print(F("AT+HTTPREAD\r"));
                            _buffer = _readSerial(10000);

                            String okuma = "";

                            if (_buffer.indexOf("+HTTPREAD:") != -1) {

                                String kriter = "+HTTPREAD: " + uzunluk;
                                String veri = _buffer.substring(_buffer.indexOf(kriter) + kriter.length(), _buffer.lastIndexOf("OK"));
                                okuma = veri;
                            }
                            else {
                                return "ERROR:HTTP_READ_ERROR";
                            }

                            String sonuc = "METHOD:GET|HTTPCODE:";
                            sonuc += kod;
                            sonuc += "|LENGTH:";
                            sonuc += uzunluk;
                            sonuc += "|DATA:";
                            okuma.trim();
                            sonuc += okuma;

                            serialManager.print(F("AT+HTTPTERM\r"));
                            _buffer = _readSerial();

                            sonuc.trim();

                            return sonuc;
                        }
                        else {
                            return "ERROR:HTTP_ACTION_READ_ERROR";
                        }
                    }
                    else {
                        return "ERROR:HTTP_ACTION_ERROR";
                    }
                }
                else {
                    return "ERROR:HTTP_PARAMETER_ERROR";
                }

            }
            else {
                return "ERROR:HTTP_PARAMETER_ERROR";
            }
        }
        else {
            return "ERROR:HTTP_INIT_ERROR";
        }
    }
    else {
        return "ERROR:GPRS_NOT_CONNECTED";
    }
}

//////////////////////////////////////
//          TIME METHODS            //
//////////////////////////////////////

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::timeSetServer(int timezone) {
    serialManager.print("AT+CNTPCID=1\r");
    _buffer = _readSerial();

    int zaman = 0;
    if (timezone <= -12) {
        zaman = -47;
    }
    if (timezone > 12) {
        zaman = 48;
    }
    if (timezone > -12 || timezone <= 12) {
        zaman = timezone * 4;
    }

    serialManager.print(F("AT+CNTP=\"202.120.2.101\","));
    serialManager.print(zaman);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::timeSetServer(int timezone, String server) {
    serialManager.print("AT+CNTPCID=1\r");
    _buffer = _readSerial();

    int zaman = 0;
    if (timezone <= -12) {
        zaman = -47;
    }
    if (timezone > 12) {
        zaman = 48;
    }
    if (timezone > -12 || timezone <= 12) {
        zaman = timezone * 4;
    }

    serialManager.print(F("AT+CNTP=\""));
    serialManager.print(server);
    serialManager.print(F("\","));
    serialManager.print(zaman);
    serialManager.print(F("\r"));

    _buffer = _readSerial();

    return (_buffer.indexOf("OK") != -1);
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::timeSyncFromServer() {

    serialManager.print(F("AT+CNTP\r"));
    _buffer = _readSerial();
    //delay(50);
    _buffer = _readSerial(20000);

    if (_buffer.indexOf("+CNTP:") != -1) {
        String kod = _buffer.substring(8);
        kod.trim();

        if (kod == "1") {
            return "TIME_SYNCHRONIZED_SUCCESS";
        }
        else if (kod == "61") {
            return "NETWORK_ERROR";
        }
        else if (kod == "62") {
            return "DNS_ERROR";
        }
        else if (kod == "63") {
            return "CONNECTION_ERROR";
        }
        else if (kod == "64") {
            return "SERVICE_RESPONSE_ERROR";
        }
        else if (kod == "65") {
            return "SERVICE_RESPONSE_TIMEOUT";
        }
        else {
            return "UNKNOWN_ERROR_" + kod;
        }
    }
    else {
        return "AT_COMMAND_ERROR";
        //return _buffer;
    }
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::timeGetRaw() {
    serialManager.print("AT+CCLK?\r");
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        String zaman = _buffer.substring(_buffer.indexOf("\"") + 1, _buffer.lastIndexOf("\""));
        return zaman;
    }
    else {
        return "ERROR:NOT_GET_DATETIME";
    }
}

template <class HWorSW_Serial>
void GSMSim_TemplateSerial<HWorSW_Serial>::timeGet(int *day, int *month, int *year, int *hour, int *minute, int *second) {
    serialManager.print("AT+CCLK?\r");
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        _buffer = _buffer.substring(_buffer.indexOf("\"") + 1, _buffer.lastIndexOf("\"") - 1);
        *year = (_buffer.substring(0, 2).toInt()) + 2000;
        *month = _buffer.substring(3, 5).toInt();
        *day = _buffer.substring(6, 8).toInt();
        *hour = _buffer.substring(9, 11).toInt();
        *minute = _buffer.substring(12, 14).toInt();
        *second = _buffer.substring(15, 17).toInt();
    }
}

//////////////////////////////////////
//          EMAIL METHODS           //
//////////////////////////////////////

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPConf(String server, String port, bool useSSL) {
    int ssl = useSSL == true ? 1 : 0;

    serialManager.print(F("AT+EMAILSSL="));
    serialManager.print(ssl);
    serialManager.print(F("\r"));
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {

        serialManager.print(F("AT+EMAILCID=1\r"));
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1) {
            serialManager.print(F("AT+EMAILTO=30\r"));
            _buffer = _readSerial();

            if (_buffer.indexOf("OK") != -1) {
                serialManager.print(F("AT+SMTPSRV=\""));
                serialManager.print(server);
                serialManager.print(F("\",\""));
                serialManager.print(port);
                serialManager.print("\"\r");

                _buffer = _readSerial();

                if (_buffer.indexOf("OK") != -1) {
                    return true;
                }
                else {
                    return false;
                }
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPAuth(String username, String password) {
    serialManager.print(F("AT+SMTPAUTH=1,\""));
    serialManager.print(username);
    serialManager.print(F("\",\""));
    serialManager.print(password);
    serialManager.print(F("\"\r"));

    _buffer = _readSerial();
    if (_buffer.indexOf("OK") != -1) {
        return true;
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPAuth(String username, String password, bool requireAuth) {
    int auth = requireAuth == true ? 1 : 0;
    serialManager.print(F("AT+SMTPAUTH="));
    serialManager.print(auth);
    serialManager.print(F(",\""));
    serialManager.print(username);
    serialManager.print(F("\",\""));
    serialManager.print(password);
    serialManager.print(F("\"\r"));

    _buffer = _readSerial();
    return (_buffer.indexOf("OK") != -1);
}

template <class HWorSW_Serial>
bool GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPGmail(String username, String password) {
    bool conf = emailSMTPConf("smtp.gmail.com", "465", true);
    if (conf) {
        return emailSMTPAuth(username, password);
    }
    else {
        return false;
    }
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPWrite(String from, String to, String title, String message) {

    serialManager.print(F("AT+SMTPFROM=\""));
    serialManager.print(from);
    serialManager.print("\"\r");
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {

        serialManager.print("AT+SMTPRCPT=0\r");
        _buffer = _readSerial();
        delay(50);
        serialManager.print(F("AT+SMTPRCPT=0,1,\""));
        serialManager.print(to);
        serialManager.print("\"\r");
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1) {

            serialManager.print(F("AT+SMTPSUB=\""));
            serialManager.print(title);
            serialManager.print("\"\r");
            _buffer = _readSerial();

            if (_buffer.indexOf("OK") != -1) {

                uint8_t uzunluk = message.length();
                serialManager.print(F("AT+SMTPBODY="));
                serialManager.print(uzunluk);
                serialManager.print("\r");

                delay(50);

                serialManager.print(message);
                serialManager.print(F("\""));
                _buffer += _readSerial();

                if (_buffer.indexOf("OK") != -1) {

                    return "OK";
                }
                else {
                    return "ERROR:BODY_NOT_SET";
                }

            }
            else {
                return "ERROR:TITLE_NOT_SET";
            }
        }
        else {
            return "ERROR:TO_NOT_SET";
        }
    }
    else {
        return "ERROR:FROM_NOT_SET";
    }
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPWrite(String from, String to, String title, String message, String fromName, String toName) {
    serialManager.print(F("AT+SMTPFROM=\""));
    serialManager.print(from);
    serialManager.print("\",\"");
    serialManager.print(fromName);
    serialManager.print("\"\r");
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {

        serialManager.print("AT+SMTPRCPT=0\r");
        _buffer = _readSerial();
        delay(50);
        serialManager.print(F("AT+SMTPRCPT=0,1,\""));
        serialManager.print(to);
        serialManager.print("\",\"");
        serialManager.print(toName);
        serialManager.print("\"\r");
        _buffer = _readSerial();

        if (_buffer.indexOf("OK") != -1) {

            serialManager.print(F("AT+SMTPSUB=\""));
            serialManager.print(title);
            serialManager.print("\"\r");
            _buffer = _readSerial();

            if (_buffer.indexOf("OK") != -1) {

                uint8_t uzunluk = message.length();
                serialManager.print(F("AT+SMTPBODY="));
                serialManager.print(uzunluk);
                serialManager.print("\r");

                delay(50);

                serialManager.print(message);
                serialManager.print(F("\""));
                _buffer += _readSerial();

                if (_buffer.indexOf("OK") != -1) {

                    return "OK";
                }
                else {
                    return "ERROR:BODY_NOT_SET";
                }

            }
            else {
                return "ERROR:TITLE_NOT_SET";
            }
        }
        else {
            return "ERROR:TO_NOT_SET";
        }
    }
    else {
        return "ERROR:FROM_NOT_SET";
    }
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::emailSMTPSend() {

    serialManager.print("AT+SMTPSEND\r");
    _buffer = _readSerial();

    if (_buffer.indexOf("OK") != -1) {
        delay(50);
        _buffer = _readSerial(30000);
        if (_buffer.indexOf("+SMTPSEND:") != -1) {
            String kod = _buffer.substring(12);
            kod.trim();

            if (kod == "1") {
                return "SUCCESS:EMAIL_SEND";
            }
            else if (kod == "61") {
                return "ERROR:NETWORK_ERROR";
            }
            else if (kod == "62") {
                return "ERROR:DNS_RESOLVE_ERROR";
            }
            else if (kod == "63") {
                return "ERROR:TCP_CONNECTION_ERROR";
            }
            else if (kod == "64") {
                return "ERROR:TIMEOUT_SMTP_RESPONSE";
            }
            else if (kod == "65") {
                return "ERROR:SMTP_RESPONSE_ERROR";
            }
            else if (kod == "66") {
                return "ERROR:NOT_AUTH";
            }
            else if (kod == "67") {
                return "ERROR:AUTH_FAILED";
            }
            else if (kod == "68") {
                return "ERROR:BAD_RECIPIENT";
            }
            else {
                return "ERROR:ERROR_NO_" + kod;
            }
        }
        else {
            delay(50);
            _buffer = _readSerial(30000);

            if (_buffer.indexOf("+SMTPSEND:") != -1) {
                String kod = _buffer.substring(12);
                kod.trim();

                if (kod == "1") {
                    return "SUCCESS:EMAIL_SEND";
                }
                else if (kod == "61") {
                    return "ERROR:NETWORK_ERROR";
                }
                else if (kod == "62") {
                    return "ERROR:DNS_RESOLVE_ERROR";
                }
                else if (kod == "63") {
                    return "ERROR:TCP_CONNECTION_ERROR";
                }
                else if (kod == "64") {
                    return "ERROR:TIMEOUT_SMTP_RESPONSE";
                }
                else if (kod == "65") {
                    return "ERROR:SMTP_RESPONSE_ERROR";
                }
                else if (kod == "66") {
                    return "ERROR:NOT_AUTH";
                }
                else if (kod == "67") {
                    return "ERROR:AUTH_FAILED";
                }
                else if (kod == "68") {
                    return "ERROR:BAD_RECIPIENT";
                }
                else {
                    return "ERROR:ERROR_NO_" + kod;
                }
            }
            else {
                return "ERROR:EMAIL_TIMEOUT_ERROR";
            }
        }
    }
    else {
        return "ERROR:EMAIL_SENDING_ERROR";
    }
}

//////////////////////////////////////
//          PRIVATE METHODS         //
//////////////////////////////////////

// READ FROM SERIAL
template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::_readSerial() {

    uint64_t timeOld = millis();

    while (!serialManager.available() && !(millis() > timeOld + TIME_OUT_READ_SERIAL))
    {
        delay(13);
    }

    String str = "";

    while (serialManager.available())
    {
        if (serialManager.available())
        {
            str += (char) serialManager.read();
      /*     ^^^^^^ might be unnecessary    */
        }
    }

    return str;
}

template <class HWorSW_Serial>
String GSMSim_TemplateSerial<HWorSW_Serial>::_readSerial(uint32_t timeout) {

    uint64_t timeOld = millis();

    while (!serialManager.available() && !(millis() > timeOld + timeout))
    {
        delay(13);
    }

    String str = "";

    while (serialManager.available())
    {
        if (serialManager.available())
        {
            str += (char) serialManager.read();
      /*     ^^^^^^ might be unnecessary    */
        }
    }

    return str;
}

#endif

All the best, Nicola

JazzTp commented 4 years ago

P.D.:

JazzTp commented 4 years ago

Please also notice that functions arguments such as

char* imeino char* phone_number char* number, char* message char* messageCenter char* code

should more appropriately be changed to const char* ... (unless you are passing a pointer to a buffer that you plan to modify from within the function).

The respective definitions should also be modified, for instance:

const char* number = "+905123456789"; const char* message = "Hi my friend. How are you?";

JazzTp commented 4 years ago

In the class declaration, you might want to consider changing private to protected in order to allow inheritance with full access to all functionalities and possibility to expand them implementing answers to users' punctual needs (I'd see no reason to deny that, protected protects enough).

JazzTp commented 4 years ago

Of course, the modified GSM example, as it is, is not meant to replace the official one.

The "which board" test is there just to remember that some amount of generalization is possible.

To make it a bit more backward compatible with your original SMS example it might go towards this direction but it would be less readable, which is why I'm not editing the SMS example in my first post above:

#ifdef BOARD_generic_stm32f103c
  #define DEFAULT_PIN_RESET PB0
  #define __SERIAL_CLASS__ HardwareSerial
  #define __SERIAL_CLASS_INSTANCE__ Serial2
#else
  // (untested)

  // ifdef statements for other boards, and/or finally back to the original example as a default:

  #define DEFAULT_PIN_RESET 2
  #include <SoftwareSerial.h>
  #define __SERIAL_CLASS__ SoftwareSerial
  #define __SERIAL_CLASS_INSTANCE__ SerialWhatever

  /* +++++ ADD PIN NUMBER DEFINITIONS AS IN ORIGINAL EXAMPLE, CREATE INSTANCE OF SoftwareSerial object */

#endif

#define BAUD 9600

GSMSim_TemplateSerial<__SERIAL_CLASS__> gsm(__SERIAL_CLASS_INSTANCE__, DEFAULT_PIN_RESET);

etc. etc.

My goal here was most evidently just to throw you the idea, the proposition, with a working quick mod of both the library and the SMS example, I'm not pretending to give a finished product (as I said, I moved on from the last official release which I see is way behind your current GitHub status).

(BTW, there's "Serial2" simply because that's the one I connected the GSM module to, with this STM32F103C8T6, aka “Blue Pill”. We are not aiming at total automatic compilation of a completely predefined sketch, anyway, it's clear that in any setup the user has room for some amount of customization... adding too many conditional compilation statements can also make it more difficult to read and maintain.)

erdemarslan commented 4 years ago

In new version any software or hardware serial will be use with this class. I will release it in a few days. Thanks

JazzTp commented 4 years ago

My pleasure. Thank you for the the nice library. :+1: