Added battery status, SMS are sent/received in Text format instead of PDU
This commit is contained in:
parent
83e50daf36
commit
a5ad4c4e1d
129
DTE.h
Normal file
129
DTE.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* DTE.h
|
||||
*
|
||||
* Created: 20/09/2016 15:40:51
|
||||
* Author: Neta Yahav
|
||||
*/
|
||||
|
||||
#ifndef __DTE_H__
|
||||
#define __DTE_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class DTE
|
||||
{
|
||||
//variables
|
||||
public:
|
||||
enum CommandResult
|
||||
{
|
||||
EXPECT_BUSY,
|
||||
EXPECT_TIMEOUT,
|
||||
EXPECT_DELAY,
|
||||
EXPECT_RESULT
|
||||
};
|
||||
|
||||
protected:
|
||||
private:
|
||||
String buffer;
|
||||
Stream& stream;
|
||||
unsigned int bufferIndex;
|
||||
unsigned int bufferSize;
|
||||
String response[3];
|
||||
unsigned long timeout;
|
||||
unsigned long tick;
|
||||
unsigned int match;
|
||||
CommandResult result;
|
||||
//functions
|
||||
public:
|
||||
DTE(Stream& stream, unsigned int size) : stream(stream), bufferSize(size), result(EXPECT_RESULT) { buffer.reserve(size); }
|
||||
~DTE() {};
|
||||
void SendCommand(const char* command, unsigned long timeout, const char* response1, const char* response2 = 0, const char* response3 = 0)
|
||||
{
|
||||
match = 0;
|
||||
result = EXPECT_BUSY;
|
||||
response[0] = response1;
|
||||
response[1] = response2;
|
||||
response[2] = response3;
|
||||
this->timeout = timeout;
|
||||
// clear rx buffer
|
||||
while (stream.available())
|
||||
{
|
||||
stream.read();
|
||||
}
|
||||
// send command
|
||||
stream.print(command);
|
||||
buffer = "";
|
||||
tick = millis();
|
||||
proccess();
|
||||
}
|
||||
void Delay(unsigned long delay)
|
||||
{
|
||||
timeout = delay;
|
||||
result = EXPECT_DELAY;
|
||||
tick = millis();
|
||||
proccess();
|
||||
}
|
||||
bool getIsBusy()
|
||||
{
|
||||
proccess();
|
||||
return (result == EXPECT_BUSY) || (result == EXPECT_DELAY);
|
||||
}
|
||||
CommandResult getResult() { return result ; }
|
||||
unsigned int getMatch() { return match; }
|
||||
String& getBuffer() { return buffer; }
|
||||
protected:
|
||||
private:
|
||||
void proccess()
|
||||
{
|
||||
if(result == EXPECT_DELAY)
|
||||
{
|
||||
if(millis() - tick >= timeout)
|
||||
result = EXPECT_RESULT;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(result != EXPECT_BUSY) return;
|
||||
|
||||
char c;
|
||||
unsigned long now = millis();
|
||||
|
||||
while(millis() - tick < timeout)
|
||||
{
|
||||
while(stream.available() && (buffer.length() < (bufferSize)))
|
||||
{
|
||||
c = stream.read();
|
||||
buffer += c;
|
||||
if(buffer.endsWith(response[0]))
|
||||
{
|
||||
match = 0;
|
||||
result = EXPECT_RESULT;
|
||||
return;
|
||||
}else if(response[1].length() != 0)
|
||||
{
|
||||
if(buffer.endsWith(response[1]))
|
||||
{
|
||||
match = 1;
|
||||
result = EXPECT_RESULT;
|
||||
return;
|
||||
}
|
||||
}else if(response[2].length() != 0)
|
||||
{
|
||||
if(buffer.endsWith(response[2]))
|
||||
{
|
||||
match = 2;
|
||||
result = EXPECT_RESULT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(millis() - now > 5)
|
||||
return;
|
||||
}
|
||||
|
||||
// time out
|
||||
result = EXPECT_TIMEOUT;
|
||||
}
|
||||
}; //DTE
|
||||
|
||||
#endif //__DTE_H__
|
79
README_original.md
Normal file
79
README_original.md
Normal file
@ -0,0 +1,79 @@
|
||||
# ArduinoThreadedGSM
|
||||
|
||||
|
||||
Use this library to:
|
||||
|
||||
* Send/Read SMS
|
||||
* Read Network Time
|
||||
* Read GSM signal level
|
||||
|
||||
### Quick-start
|
||||
|
||||
Initialize modem:
|
||||
|
||||
```c++
|
||||
ThreadedGSM modem(Serial1);
|
||||
...
|
||||
void setup()
|
||||
{
|
||||
modem.begin();
|
||||
}
|
||||
```
|
||||
Set automatic intervals for syncing clock and signal levels:
|
||||
```c++
|
||||
modem.setInterval(ThreadedGSM::INTERVAL_CLOCK, 60000);
|
||||
modem.setInterval(ThreadedGSM::INTERVAL_SIGNAL, 60000);
|
||||
modem.setInterval(ThreadedGSM::INTERVAL_INBOX, 30000);
|
||||
```
|
||||
Create your event handlers
|
||||
```c++
|
||||
void clock(ThreadedGSM& modem, ThreadedGSM::NetworkTime& Time)
|
||||
{
|
||||
/* Network time */
|
||||
}
|
||||
|
||||
void signal(ThreadedGSM& modem, ThreadedGSM::SignalLevel& Signal)
|
||||
{
|
||||
/* Signal */
|
||||
}
|
||||
|
||||
void sms(ThreadedGSM& modem, String& Msg)
|
||||
{
|
||||
/* Message received in PDU */
|
||||
}
|
||||
|
||||
void startup(ThreadedGSM& modem)
|
||||
{
|
||||
/* READY */
|
||||
}
|
||||
```
|
||||
Set event handlers for modem events as you like:
|
||||
```c++
|
||||
modem.setHandlers({
|
||||
.signal = signal,
|
||||
.clock = clock,
|
||||
.incoming = sms,
|
||||
.ready = startup,
|
||||
.outgoing = NULL,
|
||||
.power = NULL
|
||||
});
|
||||
```
|
||||
and finally, let the modem loop as a thread in your Arduino loop()
|
||||
```c++
|
||||
void loop()
|
||||
{
|
||||
// "Non-blocking" loop
|
||||
modem.loop();
|
||||
}
|
||||
```
|
||||
|
||||
To send SMS messages, request to send them using sendSMS:
|
||||
```c++
|
||||
modem.sendSMS(PDU); // PDU as String, hexadecimal
|
||||
```
|
||||
*Don't forget to check whether your messages were sent successfuly, before sending more.*
|
||||
|
||||
*Use power event callbacks to set modem pins (EN/RST) on power on/off when needed*
|
||||
|
||||
|
||||
Project hosted on GitHub: [https://github.com/neta540/ArduinoThreadedGSM](https://github.com/neta540/ArduinoThreadedGSM).
|
690
ThreadedGSM.h
Normal file
690
ThreadedGSM.h
Normal file
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* ThreadedGSM.h
|
||||
*
|
||||
* Created: 20/09/2016 11:14:02
|
||||
* Author: Neta Yahav
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __THREADEDGSM_H__
|
||||
#define __THREADEDGSM_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "DTE.h"
|
||||
|
||||
// Defaults
|
||||
#define THREADEDGSM_DEF_DTE_BUF_SIZ 512
|
||||
#define THREADEDGSM_DEF_AT_TIMEOUT 5000
|
||||
#define THREADEDGSM_DEF_STA_PON 10000
|
||||
#define THREADEDGSM_DEF_STA_POF 1000
|
||||
|
||||
// Use custom values or default ones
|
||||
#ifndef THREADEDGSM_DTE_BUFFER_SIZE
|
||||
#define THREADEDGSM_DTE_BUFFER_SIZE THREADEDGSM_DEF_DTE_BUF_SIZ
|
||||
#endif
|
||||
#ifndef THREADEDGSM_AT_TIMEOUT
|
||||
#define THREADEDGSM_AT_TIMEOUT THREADEDGSM_DEF_AT_TIMEOUT
|
||||
#endif
|
||||
#ifndef THREADEDGSM_STARTUP_DELAY
|
||||
#define THREADEDGSM_STARTUP_DELAY THREADEDGSM_DEF_STA_PON
|
||||
#endif
|
||||
#ifndef THREADEDGSM_STARTUP_POWER_OFF_DELAY
|
||||
#define THREADEDGSM_STARTUP_POWER_OFF_DELAY THREADEDGSM_DEF_STA_POF
|
||||
#endif
|
||||
|
||||
#define THREADEDGSM_INTERVAL_COUNT 4
|
||||
|
||||
#ifdef THREADEDGSM_DEBUG
|
||||
#define DEBUG_PRINT(x) THREADEDGSM_DEBUG.print (x)
|
||||
#define DEBUG_PRINTLN(x) THREADEDGSM_DEBUG.println (x)
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#endif
|
||||
|
||||
class ThreadedGSM
|
||||
{
|
||||
//variables
|
||||
public:
|
||||
struct NetworkTime
|
||||
{
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minute;
|
||||
int second;
|
||||
};
|
||||
|
||||
enum ReadMessagesListTypeE {
|
||||
READ_TYPE_UNREAD = 0,
|
||||
READ_TYPE_READ = 1,
|
||||
READ_TYPE_UNSENT = 2,
|
||||
READ_TYPE_SENT = 3,
|
||||
READ_TYPE_ALL = 4
|
||||
};
|
||||
|
||||
enum IntervalSourceE
|
||||
{
|
||||
INTERVAL_CLOCK,
|
||||
INTERVAL_INBOX,
|
||||
INTERVAL_SIGNAL,
|
||||
INTERVAL_BATTERY
|
||||
};
|
||||
|
||||
struct SignalLevel
|
||||
{
|
||||
int Dbm;
|
||||
int Value;
|
||||
};
|
||||
|
||||
struct BatteryInfo
|
||||
{
|
||||
int Percent;
|
||||
int Voltage;
|
||||
};
|
||||
|
||||
struct SMSInfo
|
||||
{
|
||||
String Number;
|
||||
String Text;
|
||||
};
|
||||
|
||||
typedef void (*ThreadedGSMCallbackSignal)(ThreadedGSM&, SignalLevel&);
|
||||
typedef void (*ThreadedGSMCallbackClock)(ThreadedGSM&, NetworkTime&);
|
||||
typedef void (*ThreadedGSMCallbackBattery)(ThreadedGSM&, BatteryInfo&);
|
||||
typedef void (*ThreadedGSMCallbackIncomingSMS)(ThreadedGSM&, SMSInfo&);
|
||||
typedef void (*ThreadedGSMCallbackBool)(ThreadedGSM&, bool);
|
||||
typedef void (*ThreadedGSMCallback)(ThreadedGSM&);
|
||||
struct conf
|
||||
{
|
||||
ThreadedGSMCallbackSignal signal;
|
||||
ThreadedGSMCallbackClock clock;
|
||||
ThreadedGSMCallbackIncomingSMS incoming;
|
||||
ThreadedGSMCallback ready;
|
||||
ThreadedGSMCallback outgoing;
|
||||
ThreadedGSMCallbackBool power;
|
||||
ThreadedGSMCallbackBattery battery;
|
||||
};
|
||||
protected:
|
||||
private:
|
||||
enum StatesStartup
|
||||
{
|
||||
STARTUP_POWER_OFF,
|
||||
STARTUP_POWER_OFF_DELAY,
|
||||
STARTUP_POWER_ON,
|
||||
STARTUP_DELAY,
|
||||
STARTUP_ENTER_AT,
|
||||
STARTUP_CHK_CPIN,
|
||||
STARTUP_CHK_CREG,
|
||||
STARTUP_CHK_CLTS,
|
||||
STARTUP_CHK_CENG
|
||||
};
|
||||
|
||||
enum StatesClock
|
||||
{
|
||||
CLOCK_REQ,
|
||||
CLOCK_VERIFY
|
||||
};
|
||||
|
||||
enum StatesSignal
|
||||
{
|
||||
SIGNAL_REQ,
|
||||
SIGNAL_VERIFY
|
||||
};
|
||||
|
||||
enum StatesBattry
|
||||
{
|
||||
BATTERY_REQ,
|
||||
BATTERY_VERIFY
|
||||
};
|
||||
|
||||
enum StatesInbox
|
||||
{
|
||||
READ_REQ,
|
||||
READ_CHK_CMGF,
|
||||
READ_CHK_CPMS,
|
||||
READ_CHK_CMGL,
|
||||
READ_DELAY_CLEAR_BUFF,
|
||||
READ_TEXT_CMGR,
|
||||
READ_CHK_CMGR,
|
||||
READ_CHK_CMGD
|
||||
};
|
||||
|
||||
enum StatesOutbox
|
||||
{
|
||||
SEND_REQ,
|
||||
SEND_CHK_CMGF,
|
||||
SEND_CHK_RDY,
|
||||
SEND_CHK_OK
|
||||
};
|
||||
|
||||
unsigned long tick;
|
||||
|
||||
struct
|
||||
{
|
||||
int Index; // Index of readed message
|
||||
}Message;
|
||||
|
||||
SMSInfo SMSi; // Inbox SMS (incoming)
|
||||
SMSInfo SMSo; // Outbox SMS (outgoing)
|
||||
|
||||
Stream& stream;
|
||||
DTE dte;
|
||||
|
||||
unsigned long tickSync[THREADEDGSM_INTERVAL_COUNT];
|
||||
unsigned long Intervals[THREADEDGSM_INTERVAL_COUNT];
|
||||
|
||||
// callbacks
|
||||
conf configuration = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
|
||||
enum ReqTypes
|
||||
{
|
||||
REQ_CLOCK = 1,
|
||||
REQ_SIG = 2,
|
||||
REQ_INBOX = 4,
|
||||
REQ_OUTBOX = 8,
|
||||
REQ_STARTUP = 16,
|
||||
REQ_BATTERY = 32,
|
||||
};
|
||||
int requests;
|
||||
int state;
|
||||
int job;
|
||||
//functions
|
||||
public:
|
||||
ThreadedGSM(Stream& stream) : stream(stream), dte(stream, THREADEDGSM_DTE_BUFFER_SIZE)
|
||||
{
|
||||
for(int i=0;i<THREADEDGSM_INTERVAL_COUNT;i++)
|
||||
Intervals[i] = 0;
|
||||
|
||||
job = state = requests = 0;
|
||||
}
|
||||
|
||||
~ThreadedGSM(){};
|
||||
|
||||
void nextJob()
|
||||
{
|
||||
job = 0;
|
||||
}
|
||||
|
||||
void setHandlers(conf config)
|
||||
{
|
||||
this->configuration = config;
|
||||
}
|
||||
|
||||
void setInterval(IntervalSourceE source, unsigned long interval)
|
||||
{
|
||||
Intervals[source] = interval;
|
||||
tickSync[source] = millis();
|
||||
}
|
||||
|
||||
// Initialization
|
||||
void begin()
|
||||
{
|
||||
requests = (REQ_STARTUP);
|
||||
}
|
||||
|
||||
// Call this function for executing thread
|
||||
void loop()
|
||||
{
|
||||
if(dte.getIsBusy()) return;
|
||||
|
||||
// intervals
|
||||
for(int i=0;i<THREADEDGSM_INTERVAL_COUNT;i++)
|
||||
{
|
||||
if(Intervals[i])
|
||||
{
|
||||
if(millis() - tickSync[i] >= Intervals[i])
|
||||
{
|
||||
switch (i) {
|
||||
case INTERVAL_CLOCK:
|
||||
requests |= REQ_CLOCK;
|
||||
break;
|
||||
case INTERVAL_INBOX:
|
||||
requests |= REQ_INBOX;
|
||||
break;
|
||||
case INTERVAL_SIGNAL:
|
||||
requests |= REQ_SIG;
|
||||
break;
|
||||
case INTERVAL_BATTERY:
|
||||
requests |= REQ_BATTERY;
|
||||
break;
|
||||
}
|
||||
tickSync[i] = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(job == 0)
|
||||
{
|
||||
// no assigned job, assign it
|
||||
if(requests & REQ_CLOCK)
|
||||
job = REQ_CLOCK;
|
||||
else if(requests & REQ_SIG)
|
||||
job = REQ_SIG;
|
||||
else if(requests & REQ_INBOX)
|
||||
job = REQ_INBOX;
|
||||
else if(requests & REQ_OUTBOX)
|
||||
job = REQ_OUTBOX;
|
||||
else if(requests & REQ_STARTUP)
|
||||
job = REQ_STARTUP;
|
||||
else if(requests & REQ_BATTERY)
|
||||
job = REQ_BATTERY;
|
||||
|
||||
if(job)
|
||||
{
|
||||
state = 0;
|
||||
DEBUG_PRINT(F("Job ID: "));
|
||||
DEBUG_PRINTLN(job);
|
||||
}
|
||||
}
|
||||
|
||||
// execute current job
|
||||
if(job == REQ_STARTUP)
|
||||
Startup();
|
||||
else if(job == REQ_CLOCK)
|
||||
Clock();
|
||||
else if(job == REQ_SIG)
|
||||
Signal();
|
||||
else if(job == REQ_INBOX)
|
||||
Inbox();
|
||||
else if(job == REQ_OUTBOX)
|
||||
Outbox();
|
||||
else if(job == REQ_BATTERY)
|
||||
Battery();
|
||||
}
|
||||
|
||||
// Requests
|
||||
void sendSMS(String& Number, String& Text)
|
||||
{
|
||||
requests |= (REQ_OUTBOX);
|
||||
SMSo.Number = Number;
|
||||
SMSo.Text = Text;
|
||||
}
|
||||
|
||||
protected:
|
||||
private:
|
||||
|
||||
// States
|
||||
void Startup()
|
||||
{
|
||||
int lastState = state;
|
||||
switch(state)
|
||||
{
|
||||
case STARTUP_POWER_OFF:
|
||||
if(this->configuration.power != NULL)
|
||||
this->configuration.power(*this, false);
|
||||
tick = millis();
|
||||
state = STARTUP_POWER_OFF_DELAY;
|
||||
break;
|
||||
case STARTUP_POWER_OFF_DELAY:
|
||||
if(millis() - tick >= THREADEDGSM_STARTUP_POWER_OFF_DELAY)
|
||||
state = STARTUP_POWER_ON;
|
||||
break;
|
||||
case STARTUP_POWER_ON:
|
||||
if(this->configuration.power != NULL)
|
||||
this->configuration.power(*this, true);
|
||||
// begin delay
|
||||
tick = millis();
|
||||
state = STARTUP_DELAY;
|
||||
break;
|
||||
case STARTUP_DELAY:
|
||||
if(millis() - tick >= THREADEDGSM_STARTUP_DELAY)
|
||||
{
|
||||
dte.SendCommand("AT\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = STARTUP_ENTER_AT;
|
||||
}
|
||||
break;
|
||||
case STARTUP_ENTER_AT:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
dte.SendCommand("AT+CPIN?\r", 10000, "OK\r");
|
||||
state = STARTUP_CHK_CPIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = STARTUP_POWER_OFF;
|
||||
}
|
||||
break;
|
||||
case STARTUP_CHK_CPIN:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
if(dte.getBuffer().indexOf("+CPIN: READY") != -1)
|
||||
{
|
||||
dte.SendCommand("AT+CREG?\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = STARTUP_CHK_CREG;
|
||||
}else
|
||||
{
|
||||
state = STARTUP_POWER_OFF;
|
||||
}
|
||||
}else
|
||||
state = STARTUP_POWER_OFF;
|
||||
break;
|
||||
case STARTUP_CHK_CREG:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
if((dte.getBuffer().indexOf(",1") >= 0) || (dte.getBuffer().indexOf(",5") >= 0))
|
||||
{
|
||||
dte.SendCommand("AT+CLTS=1\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = STARTUP_CHK_CLTS;
|
||||
}else
|
||||
state = STARTUP_POWER_OFF;
|
||||
}else
|
||||
state = STARTUP_POWER_OFF;
|
||||
break;
|
||||
case STARTUP_CHK_CLTS:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
dte.SendCommand("AT+CENG=3\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = STARTUP_CHK_CENG;
|
||||
}else
|
||||
state = STARTUP_POWER_OFF;
|
||||
break;
|
||||
case STARTUP_CHK_CENG:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
requests |= ((REQ_CLOCK)|(REQ_SIG)|(REQ_BATTERY));
|
||||
clearReq(REQ_STARTUP);
|
||||
for(int i=0;i<THREADEDGSM_INTERVAL_COUNT;i++)
|
||||
tickSync[i] = millis();
|
||||
if(this->configuration.ready != NULL)
|
||||
this->configuration.ready(*this);
|
||||
}else
|
||||
state = STARTUP_POWER_OFF;
|
||||
break;
|
||||
}
|
||||
if(state != lastState)
|
||||
{
|
||||
DEBUG_PRINT(F("STARTUP_STATE: "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
|
||||
// Threads
|
||||
void Clock()
|
||||
{
|
||||
String clockTime;
|
||||
int lastState = state;
|
||||
switch(state)
|
||||
{
|
||||
case CLOCK_REQ:
|
||||
dte.SendCommand("AT+CCLK?\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = CLOCK_VERIFY;
|
||||
break;
|
||||
case CLOCK_VERIFY:
|
||||
int index = dte.getBuffer().indexOf("+CCLK: ");
|
||||
if(index >= 0)
|
||||
{
|
||||
// parse clock
|
||||
index+=8;
|
||||
int endindex;
|
||||
endindex = dte.getBuffer().indexOf("+", index);
|
||||
if(endindex >= 0)
|
||||
clockTime = dte.getBuffer().substring(index, endindex);
|
||||
else
|
||||
{
|
||||
endindex = dte.getBuffer().indexOf("-", index);
|
||||
if(endindex >= 0)
|
||||
clockTime = dte.getBuffer().substring(index, endindex);
|
||||
}
|
||||
|
||||
if(endindex >= 0)
|
||||
{
|
||||
NetworkTime ClockTime;
|
||||
ClockTime.year = 2000+clockTime.substring(0,2).toInt();
|
||||
ClockTime.month = clockTime.substring(3,5).toInt();
|
||||
ClockTime.day = clockTime.substring(6,8).toInt();
|
||||
ClockTime.hour = clockTime.substring(9,11).toInt();
|
||||
ClockTime.minute = clockTime.substring(12,14).toInt();
|
||||
ClockTime.second = clockTime.substring(15,17).toInt();
|
||||
if(this->configuration.clock != NULL)
|
||||
this->configuration.clock(*this, ClockTime);
|
||||
}
|
||||
}
|
||||
clearReq(REQ_CLOCK);
|
||||
break;
|
||||
}
|
||||
if(state != lastState)
|
||||
{
|
||||
DEBUG_PRINT(F("CLOCK_STATE: "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
void Signal()
|
||||
{
|
||||
int lastState = state;
|
||||
switch(state)
|
||||
{
|
||||
case SIGNAL_REQ:
|
||||
dte.SendCommand("AT+CSQ\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = SIGNAL_VERIFY;
|
||||
break;
|
||||
case SIGNAL_VERIFY:
|
||||
int index = dte.getBuffer().indexOf("+CSQ: ");
|
||||
if(index >= 0)
|
||||
{
|
||||
// parse signal
|
||||
index+=6;
|
||||
SignalLevel GsmSignal;
|
||||
GsmSignal.Value = dte.getBuffer().substring(index,index+2).toInt();
|
||||
GsmSignal.Dbm = dte.getBuffer().substring(index+3,index+5).toInt();
|
||||
if(GsmSignal.Value != 0)
|
||||
{
|
||||
if(this->configuration.signal != NULL)
|
||||
this->configuration.signal(*this, GsmSignal);
|
||||
}
|
||||
}
|
||||
clearReq(REQ_SIG);
|
||||
break;
|
||||
}
|
||||
if(state != lastState)
|
||||
{
|
||||
DEBUG_PRINT(F("SIGNAL_STATE: "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
|
||||
void Battery()
|
||||
{
|
||||
int lastState = state;
|
||||
switch(state)
|
||||
{
|
||||
case BATTERY_REQ:
|
||||
dte.SendCommand("AT+CBC\r", THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = BATTERY_VERIFY;
|
||||
break;
|
||||
case BATTERY_VERIFY:
|
||||
int index = dte.getBuffer().indexOf("+CBC:");
|
||||
if(index >= 0)
|
||||
{
|
||||
BatteryInfo BattInfo;
|
||||
// parse battery level
|
||||
String buffer = dte.getBuffer().substring(index);
|
||||
String buffer2 = buffer.substring(buffer.indexOf(",") + 1);
|
||||
buffer = buffer2;
|
||||
BattInfo.Percent = buffer2.substring(0, buffer2.indexOf(",")).toInt(); // converts the result to interger
|
||||
buffer2 = buffer.substring(buffer.indexOf(",") + 1);
|
||||
BattInfo.Voltage = buffer2.substring(0, buffer2.indexOf("\r")).toInt(); // converts the result to interger
|
||||
if(this->configuration.battery != NULL)
|
||||
this->configuration.battery(*this, BattInfo);
|
||||
}
|
||||
clearReq(REQ_BATTERY);
|
||||
break;
|
||||
}
|
||||
if(state != lastState)
|
||||
{
|
||||
DEBUG_PRINT(F("BATTERY_STATE: "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
|
||||
void clearReq(int req)
|
||||
{
|
||||
requests &= ~(req);
|
||||
nextJob();
|
||||
}
|
||||
void Inbox()
|
||||
{
|
||||
String CMD;
|
||||
int lastState = state;
|
||||
switch(state)
|
||||
{
|
||||
case READ_REQ:
|
||||
SMSi.Text = "";
|
||||
SMSi.Number = "";
|
||||
dte.SendCommand("AT+CMGF=0\r", THREADEDGSM_AT_TIMEOUT, "OK\r"); // SMS Message format set as PDU
|
||||
state = READ_CHK_CMGF;
|
||||
break;
|
||||
case READ_CHK_CMGF:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
dte.SendCommand("AT+CPMS=\"SM\"\r", THREADEDGSM_AT_TIMEOUT, "OK\r"); // SIM Message storage
|
||||
state = READ_CHK_CPMS;
|
||||
}
|
||||
else clearReq(REQ_INBOX);
|
||||
break;
|
||||
case READ_CHK_CPMS:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
CMD = F("AT+CMGL="); // Read all SMS messages
|
||||
CMD += (int) READ_TYPE_ALL;
|
||||
CMD += "\r";
|
||||
dte.SendCommand(CMD.c_str(), THREADEDGSM_AT_TIMEOUT, ",");
|
||||
state = READ_CHK_CMGL;
|
||||
}
|
||||
else clearReq(REQ_INBOX);
|
||||
break;
|
||||
case READ_CHK_CMGL:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
//fetch index
|
||||
int indexStart = dte.getBuffer().indexOf("+CMGL: ");
|
||||
if (indexStart >= 0)
|
||||
{
|
||||
Message.Index = dte.getBuffer().substring(indexStart + 7, dte.getBuffer().indexOf(",")).toInt();
|
||||
if(Message.Index != 0)
|
||||
{
|
||||
dte.Delay(2000);
|
||||
state = READ_DELAY_CLEAR_BUFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(state != READ_DELAY_CLEAR_BUFF)
|
||||
clearReq(REQ_INBOX);
|
||||
|
||||
break;
|
||||
|
||||
case READ_DELAY_CLEAR_BUFF:
|
||||
dte.SendCommand("AT+CMGF=1\r", THREADEDGSM_AT_TIMEOUT, "OK\r"); // SMS Message format set as TEXT
|
||||
state = READ_TEXT_CMGR;
|
||||
break;
|
||||
|
||||
case READ_TEXT_CMGR:
|
||||
if (dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
CMD = F("AT+CMGR="); // Read the SMS message
|
||||
CMD += Message.Index;
|
||||
CMD += "\r";
|
||||
dte.SendCommand(CMD.c_str(), THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = READ_CHK_CMGR;
|
||||
}else
|
||||
clearReq(REQ_INBOX);
|
||||
break;
|
||||
|
||||
case READ_CHK_CMGR:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
int indexStart = dte.getBuffer().indexOf("+CMGR: ");
|
||||
if(indexStart >= 0)
|
||||
{
|
||||
int indexStartPDU = dte.getBuffer().indexOf("\r\n", indexStart);
|
||||
if (indexStartPDU >= 0)
|
||||
{
|
||||
indexStartPDU+=2;
|
||||
int indexEndPDU = dte.getBuffer().indexOf("\r", indexStartPDU);
|
||||
if(indexEndPDU >= 0)
|
||||
SMSi.Text = dte.getBuffer().substring(indexStartPDU, indexEndPDU);
|
||||
}
|
||||
indexStartPDU = dte.getBuffer().indexOf(",\"", indexStart);
|
||||
if (indexStartPDU >= 0)
|
||||
{
|
||||
indexStartPDU += 2;
|
||||
int indexEndPDU = dte.getBuffer().indexOf("\",", indexStartPDU);
|
||||
if (indexEndPDU >= 0)
|
||||
SMSi.Number = dte.getBuffer().substring(indexStartPDU, indexEndPDU);
|
||||
}
|
||||
}
|
||||
CMD = F("AT+CMGD="); // Delete the SMS message
|
||||
CMD += Message.Index;
|
||||
CMD += "\r";
|
||||
dte.SendCommand(CMD.c_str(), THREADEDGSM_AT_TIMEOUT, "OK\r");
|
||||
state = READ_CHK_CMGD;
|
||||
}else
|
||||
clearReq(REQ_INBOX);
|
||||
break;
|
||||
case READ_CHK_CMGD:
|
||||
//if( (dte.getResult() == DTE::EXPECT_RESULT) && (SMS.InboxMsgContents != ""))
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
if(this->configuration.incoming != NULL)
|
||||
this->configuration.incoming(*this, SMSi);
|
||||
}
|
||||
clearReq(REQ_INBOX);
|
||||
break;
|
||||
}
|
||||
if(state != lastState)
|
||||
{
|
||||
DEBUG_PRINT(F("INBOX_STATE: "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
|
||||
void Outbox()
|
||||
{
|
||||
String CMD;
|
||||
int lastState = state;
|
||||
switch(state)
|
||||
{
|
||||
case SEND_REQ:
|
||||
dte.SendCommand("AT+CMGF=1\r", THREADEDGSM_AT_TIMEOUT, "OK\r"); // SMS Text mode
|
||||
state = SEND_CHK_CMGF;
|
||||
break;
|
||||
|
||||
case SEND_CHK_CMGF:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
CMD = F("AT+CMGS=\"");
|
||||
CMD += SMSo.Number;
|
||||
CMD += "\"\r";
|
||||
dte.SendCommand(CMD.c_str(), 15000, "> ");
|
||||
state = SEND_CHK_RDY;
|
||||
}
|
||||
else clearReq(REQ_OUTBOX);
|
||||
break;
|
||||
case SEND_CHK_RDY:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
CMD = SMSo.Text;
|
||||
CMD += (char)26;
|
||||
dte.SendCommand(CMD.c_str(), 10000, "OK\r");
|
||||
state = SEND_CHK_OK;
|
||||
}else clearReq(REQ_OUTBOX);
|
||||
break;
|
||||
case SEND_CHK_OK:
|
||||
if(dte.getResult() == DTE::EXPECT_RESULT)
|
||||
{
|
||||
if(this->configuration.outgoing != NULL)
|
||||
this->configuration.outgoing(*this);
|
||||
}
|
||||
clearReq(REQ_OUTBOX);
|
||||
break;
|
||||
}
|
||||
if(state != lastState)
|
||||
{
|
||||
DEBUG_PRINT(F("OUTBOX_STATE: "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
}; //ThreadedGSM
|
||||
|
||||
#endif //__THREADEDGSM_H__
|
71
examples/example1.cpp
Normal file
71
examples/example1.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* ThreadedGSM Example: Read SMS, Network Time and Signal level
|
||||
* Reads SMS messages in PDU mode and prints them to debug serial
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#define SerialDebug Serial1
|
||||
#define SerialModem Serial
|
||||
#define THREADEDGSM_DEBUG SerialDebug
|
||||
#include <ThreadedGSM.h>
|
||||
|
||||
ThreadedGSM SIM900(SerialModem);
|
||||
|
||||
void clock(ThreadedGSM& modem, ThreadedGSM::NetworkTime& Time)
|
||||
{
|
||||
SerialDebug.print("Modem Time: ");
|
||||
SerialDebug.print(Time.day);
|
||||
SerialDebug.print("/");
|
||||
SerialDebug.print(Time.month);
|
||||
SerialDebug.print("/");
|
||||
SerialDebug.print(Time.year);
|
||||
SerialDebug.print(" ");
|
||||
SerialDebug.print(Time.hour);
|
||||
SerialDebug.print(":");
|
||||
SerialDebug.print(Time.minute);
|
||||
SerialDebug.print(":");
|
||||
SerialDebug.println(Time.second);
|
||||
}
|
||||
|
||||
void signal(ThreadedGSM& modem, ThreadedGSM::SignalLevel& Signal)
|
||||
{
|
||||
SerialDebug.print("Modem signal: Dbm:");
|
||||
SerialDebug.print(Signal.Dbm);
|
||||
SerialDebug.print(" value: ");
|
||||
SerialDebug.println(Signal.Value);
|
||||
}
|
||||
|
||||
void sms(ThreadedGSM& modem, String& Msg)
|
||||
{
|
||||
SerialDebug.print("Received SMS: ");
|
||||
SerialDebug.println(Msg);
|
||||
}
|
||||
|
||||
void startup(ThreadedGSM& modem)
|
||||
{
|
||||
SerialDebug.print("Ready");
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
SerialDebug.begin(115200);
|
||||
SerialModem.begin(115200);
|
||||
SerialDebug.println("STARTUP\r\n");
|
||||
|
||||
SIM900.begin();
|
||||
SIM900.setInterval(ThreadedGSM::INTERVAL_CLOCK, 60000);
|
||||
SIM900.setInterval(ThreadedGSM::INTERVAL_SIGNAL, 60000);
|
||||
SIM900.setInterval(ThreadedGSM::INTERVAL_INBOX, 30000);
|
||||
SIM900.setHandlers({
|
||||
.signal = signal,
|
||||
.clock = clock,
|
||||
.incoming = sms,
|
||||
.ready = startup,
|
||||
.outgoing = NULL,
|
||||
.power = NULL
|
||||
});
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
SIM900.loop();
|
||||
}
|
29
library.json
Normal file
29
library.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "ThreadedGSM",
|
||||
"keywords": "gsm, sim800, sim900, sms, sim800l",
|
||||
"description": "Non-blocking Arduino GSM Library with SMS support",
|
||||
"version": "1.0.0",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "http://git.xpablo.cz/xPablo.cz/ThreadedGSM.git"
|
||||
},
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Neta Yahav",
|
||||
"email": "neta540@gmail.com",
|
||||
"maintainer": false
|
||||
},
|
||||
{
|
||||
"name": "Pavel Brychta",
|
||||
"email": "pablo@xpablo.cz",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
"examples": [
|
||||
"[Ee]xamples/*.cpp"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user