From e2c5e5dcd94d28746b0dd564269feb34dc5fef69 Mon Sep 17 00:00:00 2001 From: Pavel Brychta Date: Mon, 8 Nov 2021 13:02:56 +0100 Subject: [PATCH] WIP: pridani ring indikace (zatim nefunkcni) --- src/DTE.h | 119 +++-- src/ThreadedGSM.h | 1208 ++++++++++++++++++++++----------------------- 2 files changed, 662 insertions(+), 665 deletions(-) diff --git a/src/DTE.h b/src/DTE.h index 3dc876e..072bf84 100644 --- a/src/DTE.h +++ b/src/DTE.h @@ -5,24 +5,22 @@ * Author: Neta Yahav */ -#ifndef __DTE_H__ -#define __DTE_H__ +#pragma once #include class DTE { -//variables public: enum CommandResult { EXPECT_BUSY, EXPECT_TIMEOUT, EXPECT_DELAY, - EXPECT_RESULT + EXPECT_RESULT, + EXPECT_RING }; -protected: private: String buffer; Stream& stream; @@ -33,33 +31,32 @@ private: 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(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) - { + + 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 + flush(); stream.print(command); buffer = ""; tick = millis(); proccess(); } - void SendCommand(const __FlashStringHelper* command, unsigned long timeout, const char* response1, const char* response2 = 0, const char* response3 = 0) - { -// char cmd[32]; + void SendCommand(const __FlashStringHelper* command, unsigned long timeout, const char* response1, const char* response2 = 0, const char* response3 = 0) { match = 0; result = EXPECT_BUSY; @@ -68,81 +65,97 @@ public: response[2] = response3; this->timeout = timeout; // clear rx buffer - while (stream.available()) - { - stream.read(); - } + flush(); // send command -// strcpy_P(cmd, command); stream.print((const __FlashStringHelper *)command); -// stream.print(cmd); buffer = ""; tick = millis(); proccess(); } - void Delay(unsigned long delay) - { + void Delay(unsigned long delay) { timeout = delay; result = EXPECT_DELAY; tick = millis(); proccess(); } - bool getIsBusy() - { + + bool getIsBusy(void) { proccess(); return (result == EXPECT_BUSY) || (result == EXPECT_DELAY); } - CommandResult getResult() { return result ; } - unsigned int getMatch() { return match; } - String& getBuffer() { return buffer; } -protected: + + CommandResult getResult(void) { + return result; + } + + unsigned int getMatch(void) { + return match; + } + + String& getBuffer(void) { + return buffer; + } + private: - void proccess() - { - if(result == EXPECT_DELAY) - { + + void flush(void) { + // clear rx buffer + while (stream.available()) { + stream.read(); + } + } + + void proccess(void) { + if (result == EXPECT_DELAY) { if(millis() - tick >= timeout) result = EXPECT_RESULT; return; } - if(result != EXPECT_BUSY) return; + if (result != EXPECT_BUSY) { + if (stream.available()) { + char c; + + c = stream.read(); + buffer += c; + if (buffer.length() > 4) { + if (buffer.endsWith(F("RING\n"))) { + result = EXPECT_RING; + } + buffer.remove(0); + } + } + return; + } char c; unsigned long now = millis(); - while(millis() - tick < timeout) - { - while(stream.available() && (buffer.length() < (bufferSize))) - { + while (millis() - tick < timeout) { + while (stream.available() && (buffer.length() < bufferSize)) { c = stream.read(); buffer += c; - if(buffer.endsWith(response[0])) - { + if (buffer.endsWith(response[0])) { match = 0; result = EXPECT_RESULT; return; - }else if(response[1].length() != 0) - { - if(buffer.endsWith(response[1])) - { + } 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])) - { + } else if (response[2].length() != 0) { + if (buffer.endsWith(response[2])) { match = 2; result = EXPECT_RESULT; return; } } } - if(millis() - now > 5) + if (millis() - now > 5) return; } @@ -150,5 +163,3 @@ private: result = EXPECT_TIMEOUT; } }; //DTE - -#endif //__DTE_H__ diff --git a/src/ThreadedGSM.h b/src/ThreadedGSM.h index c977dbd..17f4caa 100644 --- a/src/ThreadedGSM.h +++ b/src/ThreadedGSM.h @@ -5,699 +5,685 @@ * Author: Neta Yahav */ - -#ifndef __THREADEDGSM_H__ -#define __THREADEDGSM_H__ +#pragma once #include #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 +#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 +# define THREADEDGSM_DTE_BUFFER_SIZE THREADEDGSM_DEF_DTE_BUF_SIZ #endif #ifndef THREADEDGSM_AT_TIMEOUT -#define THREADEDGSM_AT_TIMEOUT THREADEDGSM_DEF_AT_TIMEOUT +# define THREADEDGSM_AT_TIMEOUT THREADEDGSM_DEF_AT_TIMEOUT #endif #ifndef THREADEDGSM_STARTUP_DELAY -#define THREADEDGSM_STARTUP_DELAY THREADEDGSM_DEF_STA_PON +# 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 +# define THREADEDGSM_STARTUP_POWER_OFF_DELAY THREADEDGSM_DEF_STA_POF #endif -#define THREADEDGSM_INTERVAL_COUNT 4 +#define THREADEDGSM_INTERVAL_COUNT 4 #ifdef THREADEDGSM_DEBUG - #define DEBUG_PRINT(x) THREADEDGSM_DEBUG.print (x) - #define DEBUG_PRINTLN(x) THREADEDGSM_DEBUG.println (x) +# 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) +# 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; - }; + 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 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 - }; + enum IntervalSourceE + { + INTERVAL_CLOCK, + INTERVAL_INBOX, + INTERVAL_SIGNAL, + INTERVAL_BATTERY + }; - struct SignalLevel - { - int Dbm; - int Value; - }; + struct SignalLevel + { + int Dbm; + int Value; + }; - struct BatteryInfo - { - int Percent; - int Voltage; - }; + struct BatteryInfo + { + int Percent; + int Voltage; + }; - struct SMSInfo - { - String Number; - String Text; - }; + 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; - }; + 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&); + typedef void (*ThreadedGSMCallbackRing)(ThreadedGSM&, String&); + struct conf + { + ThreadedGSMCallbackSignal signal; + ThreadedGSMCallbackClock clock; + ThreadedGSMCallbackIncomingSMS incoming; + ThreadedGSMCallback ready; + ThreadedGSMCallback outgoing; + ThreadedGSMCallbackBool power; + ThreadedGSMCallbackBattery battery; + ThreadedGSMCallbackRing ring; + }; 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 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 StatesClock + { + CLOCK_REQ, + CLOCK_VERIFY + }; - enum StatesSignal - { - SIGNAL_REQ, - SIGNAL_VERIFY - }; + enum StatesSignal + { + SIGNAL_REQ, + SIGNAL_VERIFY + }; - enum StatesBattry - { - BATTERY_REQ, - BATTERY_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 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 - }; + enum StatesOutbox + { + SEND_REQ, + SEND_CHK_CMGF, + SEND_CHK_RDY, + SEND_CHK_OK + }; - unsigned long tick; + enum StatesCheckRing + { + RING_WAIT, + RING_CHK, + }; - struct - { - int Index; // Index of readed message - }Message; + unsigned long tick; - SMSInfo SMSi; // Inbox SMS (incoming) - SMSInfo SMSo; // Outbox SMS (outgoing) + struct + { + int Index; // Index of readed message + } Message; - Stream& stream; - DTE dte; + SMSInfo SMSi; // Inbox SMS (incoming) + SMSInfo SMSo; // Outbox SMS (outgoing) - unsigned long tickSync[THREADEDGSM_INTERVAL_COUNT]; - unsigned long Intervals[THREADEDGSM_INTERVAL_COUNT]; + Stream& stream; + DTE dte; - // callbacks - conf configuration = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + unsigned long tickSync[THREADEDGSM_INTERVAL_COUNT]; + unsigned long Intervals[THREADEDGSM_INTERVAL_COUNT]; - 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; + // callbacks +// conf configuration = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; + conf configuration{0}; + + 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; + int ringState; //functions public: - ThreadedGSM(Stream& stream) : stream(stream), dte(stream, THREADEDGSM_DTE_BUFFER_SIZE) - { - for(int i=0;iconfiguration = config; - } + void setHandlers(conf config) { - void setInterval(IntervalSourceE source, unsigned long interval) - { - Intervals[source] = interval; - tickSync[source] = millis(); - } + this->configuration = config; + } - // Initialization - void begin() - { - requests = (REQ_STARTUP); - } + void setInterval(IntervalSourceE source, unsigned long interval) { + Intervals[source] = interval; + tickSync[source] = millis(); + } - // Call this function for executing thread - void loop() - { - if(dte.getIsBusy()) return; + // Initialization + void begin(void) { + requests = (REQ_STARTUP); + } - // intervals - for(int i=0;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(); - } - } - } + // Call this function for executing thread + void loop(void) { + if (dte.getIsBusy()) + return; - 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; + // 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; - if(job) - { - state = 0; - DEBUG_PRINT(F("Job ID: ")); - DEBUG_PRINTLN(job); - } - } + case INTERVAL_INBOX: + requests |= REQ_INBOX; + break; - // 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(); - } + case INTERVAL_SIGNAL: + requests |= REQ_SIG; + break; - // Requests - void sendSMS(String& Number, String& Text) - { - requests |= (REQ_OUTBOX); - SMSo.Number = Number; - SMSo.Text = Text; - } + case INTERVAL_BATTERY: + requests |= REQ_BATTERY; + break; + } + tickSync[i] = millis(); + } + } + } - void sendSMS(String& Number, char *Text) - { + 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(); + else CheckRing(); + } + + // Requests + void sendSMS(String& Number, String& Text) { requests |= (REQ_OUTBOX); SMSo.Number = Number; SMSo.Text = Text; } + void sendSMS(String& Number, char *Text) { + String t = Text; + + sendSMS(Number, t); + } + 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(F("AT\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); - state = STARTUP_ENTER_AT; - } - break; - case STARTUP_ENTER_AT: - if(dte.getResult() == DTE::EXPECT_RESULT) - { - dte.SendCommand(F("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(F("+CPIN: READY")) != -1) - { - dte.SendCommand(F("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(F(",1")) >= 0) || (dte.getBuffer().indexOf(F(",5")) >= 0)) - { - dte.SendCommand(F("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(F("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;iconfiguration.ready != NULL) - this->configuration.ready(*this); - }else - state = STARTUP_POWER_OFF; - break; - } - if(state != lastState) - { - DEBUG_PRINT(F("STARTUP_STATE: ")); - DEBUG_PRINTLN(state); - } - } + // States + void Startup(void) { + 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; - // Threads - void Clock() - { - String clockTime; - int lastState = state; - switch(state) - { - case CLOCK_REQ: - dte.SendCommand(F("AT+CCLK?\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); - state = CLOCK_VERIFY; - break; - case CLOCK_VERIFY: - int index = dte.getBuffer().indexOf(F("+CCLK: ")); - if(index >= 0) - { - // parse clock - index+=8; - int endindex; - endindex = dte.getBuffer().indexOf(F("+"), index); - if(endindex >= 0) - clockTime = dte.getBuffer().substring(index, endindex); - else - { - endindex = dte.getBuffer().indexOf(F("-"), index); - if(endindex >= 0) - clockTime = dte.getBuffer().substring(index, endindex); - } + case STARTUP_POWER_OFF_DELAY: + if (millis() - tick >= THREADEDGSM_STARTUP_POWER_OFF_DELAY) + state = STARTUP_POWER_ON; + break; - 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); - } - } + case STARTUP_POWER_ON: + if (this->configuration.power != NULL) + this->configuration.power(*this, true); + // begin delay + tick = millis(); + state = STARTUP_DELAY; + break; - void Signal() - { - int lastState = state; - switch(state) - { - case SIGNAL_REQ: - dte.SendCommand(F("AT+CSQ\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); - state = SIGNAL_VERIFY; - break; - case SIGNAL_VERIFY: - int index = dte.getBuffer().indexOf(F("+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); - } - } + case STARTUP_DELAY: + if (millis() - tick >= THREADEDGSM_STARTUP_DELAY) { + dte.SendCommand(F("AT\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = STARTUP_ENTER_AT; + } + break; - void Battery() - { - int lastState = state; - switch(state) - { - case BATTERY_REQ: - dte.SendCommand(F("AT+CBC\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); - state = BATTERY_VERIFY; - break; - case BATTERY_VERIFY: - int index = dte.getBuffer().indexOf(F("+CBC:")); - if(index >= 0) - { - BatteryInfo BattInfo; - // parse battery level - String buffer = dte.getBuffer().substring(index); - String buffer2 = buffer.substring(buffer.indexOf(F(",")) + 1); - buffer = buffer2; - BattInfo.Percent = buffer2.substring(0, buffer2.indexOf(F(","))).toInt(); // converts the result to interger - buffer2 = buffer.substring(buffer.indexOf(F(",")) + 1); - BattInfo.Voltage = buffer2.substring(0, buffer2.indexOf(F("\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); - } - } + case STARTUP_ENTER_AT: + if (dte.getResult() == DTE::EXPECT_RESULT) { + dte.SendCommand(F("AT+CPIN?\r"), 10000, "OK\r"); + state = STARTUP_CHK_CPIN; + } else { + state = STARTUP_POWER_OFF; + } + break; - void clearReq(int req) - { - requests &= ~(req); - nextJob(); - } + case STARTUP_CHK_CPIN: + if (dte.getResult() == DTE::EXPECT_RESULT) { + if (dte.getBuffer().indexOf(F("+CPIN: READY")) != -1) { + dte.SendCommand(F("AT+CREG?\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = STARTUP_CHK_CREG; + } else { + state = STARTUP_POWER_OFF; + } + } else + state = STARTUP_POWER_OFF; + break; - void Inbox() - { - String CMD; - int lastState = state; - switch(state) - { - case READ_REQ: - SMSi.Text = ""; - SMSi.Number = ""; - dte.SendCommand(F("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(F("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(F("+CMGL: ")); - if (indexStart >= 0) - { - Message.Index = dte.getBuffer().substring(indexStart + 7, dte.getBuffer().indexOf(F(","))).toInt(); - if(Message.Index != 0) - { - dte.Delay(2000); - state = READ_DELAY_CLEAR_BUFF; - } - } - } - if(state != READ_DELAY_CLEAR_BUFF) - clearReq(REQ_INBOX); + case STARTUP_CHK_CREG: + if (dte.getResult() == DTE::EXPECT_RESULT) { + if ((dte.getBuffer().indexOf(F(",1")) >= 0) || (dte.getBuffer().indexOf(F(",5")) >= 0)) { + dte.SendCommand(F("AT+CLTS=1\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = STARTUP_CHK_CLTS; + } else + state = STARTUP_POWER_OFF; + } else + state = STARTUP_POWER_OFF; + break; - break; + case STARTUP_CHK_CLTS: + if (dte.getResult() == DTE::EXPECT_RESULT) { + dte.SendCommand(F("AT+CENG=3\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = STARTUP_CHK_CENG; + } else + state = STARTUP_POWER_OFF; + break; - case READ_DELAY_CLEAR_BUFF: - dte.SendCommand(F("AT+CMGF=1\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); // SMS Message format set as TEXT - state = READ_TEXT_CMGR; - 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); + } + } - 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; + // Threads + void Clock(void) { + String clockTime; + int lastState = state; + switch (state) { + case CLOCK_REQ: + dte.SendCommand(F("AT+CCLK?\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = CLOCK_VERIFY; + break; - case READ_CHK_CMGR: - if(dte.getResult() == DTE::EXPECT_RESULT) - { - int indexStart = dte.getBuffer().indexOf(F("+CMGR: ")); - if(indexStart >= 0) - { - int indexStartPDU = dte.getBuffer().indexOf(F("\r\n"), indexStart); - if (indexStartPDU >= 0) - { - indexStartPDU+=2; - int indexEndPDU = dte.getBuffer().indexOf(F("\r"), indexStartPDU); - if(indexEndPDU >= 0) - SMSi.Text = dte.getBuffer().substring(indexStartPDU, indexEndPDU); - } - indexStartPDU = dte.getBuffer().indexOf(F(",\""), indexStart); - if (indexStartPDU >= 0) - { - indexStartPDU += 2; - int indexEndPDU = dte.getBuffer().indexOf(F("\","), 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); - } - } + case CLOCK_VERIFY: + int index = dte.getBuffer().indexOf(F("+CCLK: ")); + if (index >= 0) { + // parse clock + index += 8; + int endindex; + endindex = dte.getBuffer().indexOf(F("+"), index); + if (endindex >= 0) + clockTime = dte.getBuffer().substring(index, endindex); + else { + endindex = dte.getBuffer().indexOf(F("-"), index); + if (endindex >= 0) + clockTime = dte.getBuffer().substring(index, endindex); + } - void Outbox() - { - String CMD; + 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(void) { + int lastState = state; + switch (state) { + case SIGNAL_REQ: + dte.SendCommand(F("AT+CSQ\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = SIGNAL_VERIFY; + break; + + case SIGNAL_VERIFY: + int index = dte.getBuffer().indexOf(F("+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(void) { + int lastState = state; + switch (state) { + case BATTERY_REQ: + dte.SendCommand(F("AT+CBC\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); + state = BATTERY_VERIFY; + break; + + case BATTERY_VERIFY: + int index = dte.getBuffer().indexOf(F("+CBC:")); + if (index >= 0) { + BatteryInfo BattInfo; + // parse battery level + String buffer = dte.getBuffer().substring(index); + String buffer2 = buffer.substring(buffer.indexOf(F(",")) + 1); + buffer = buffer2; + BattInfo.Percent = buffer2.substring(0, buffer2.indexOf(F(","))).toInt(); // converts the result to interger + buffer2 = buffer.substring(buffer.indexOf(F(",")) + 1); + BattInfo.Voltage = buffer2.substring(0, buffer2.indexOf(F("\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(void) { + String CMD; + int lastState = state; + switch (state) { + case READ_REQ: + SMSi.Text = ""; + SMSi.Number = ""; + dte.SendCommand(F("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(F("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(F("+CMGL: ")); + if (indexStart >= 0) { + Message.Index = dte.getBuffer().substring(indexStart + 7, dte.getBuffer().indexOf(F(","))).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(F("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(F("+CMGR: ")); + if (indexStart >= 0) { + int indexStartPDU = dte.getBuffer().indexOf(F("\r\n"), indexStart); + if (indexStartPDU >= 0) { + indexStartPDU += 2; + int indexEndPDU = dte.getBuffer().indexOf(F("\r"), indexStartPDU); + if (indexEndPDU >= 0) + SMSi.Text = dte.getBuffer().substring(indexStartPDU, indexEndPDU); + } + indexStartPDU = dte.getBuffer().indexOf(F(",\""), indexStart); + if (indexStartPDU >= 0) { + indexStartPDU += 2; + int indexEndPDU = dte.getBuffer().indexOf(F("\","), 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(void) { + String CMD; //CMD.reserve(200); - int lastState = state; - switch(state) - { - case SEND_REQ: - dte.SendCommand(F("AT+CMGF=1\r"), THREADEDGSM_AT_TIMEOUT, "OK\r"); // SMS Text mode - state = SEND_CHK_CMGF; - break; + int lastState = state; + switch (state) { + case SEND_REQ: + dte.SendCommand(F("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); - } - } + 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); + } + } + + void CheckRing(void) { + int lastState = ringState; + switch (ringState) { + case RING_WAIT: + if (dte.getResult() == DTE::EXPECT_RING) { + + ringState = RING_CHK; + } + break; + } + if (ringState != lastState) { + DEBUG_PRINT(F("RING_STATE: ")); + DEBUG_PRINTLN(ringState); + } + } }; //ThreadedGSM - -#endif //__THREADEDGSM_H__