Skip to content

Commit

Permalink
Support for new sms notification & AT+CMGR command
Browse files Browse the repository at this point in the history
  • Loading branch information
yeganemehr committed Sep 8, 2023
1 parent 1dd2dab commit c3ee176
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 47 deletions.
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
"platforms": "*",
"homepage": "https://github.com/yeganemehr/arduino-sim800",
"dependencies": {
"yeganemehr/arduino-at": "^0.2.0"
"yeganemehr/arduino-at": "^0.2.1"
}
}
29 changes: 29 additions & 0 deletions src/Sim800.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ void Sim800::onAtNotification(const ATNotificationEvent *e)
this->emit(&e);
return;
}
if (e->content.indexOf("+CMTI") >= 0)
{
Sim800IncomingSMSEvent evt;
if (Sim800IncomingSMSEvent::parseCMTI(&evt, e->content))
{
this->emit(&evt);
}
return;
}
}

Promise<void> *Sim800::checkConnection() const
Expand Down Expand Up @@ -245,3 +254,23 @@ Promise<String> *Sim800::getICCID() const
{
return at->execute("AT+CCID");
}

Promise<SMS *> *Sim800::getSMS(uint8_t index, bool changeStatus) const
{
auto promise = new Promise<SMS *>();
char command[14];
sprintf(command, "AT+CMGR=%hhu,%hhu", index, changeStatus ? 1 : 0);
at->execute(command)
->onSuccess([promise, index](const String &result) {
auto sms = SMS::parseCMGR(result);
if (sms) {
sms->setId(index);
promise->resolve(sms);
} else {
promise->reject(std::exception());
}
})
->redirectRejectTo(promise)
->freeOnFinish();
return promise;
}
1 change: 1 addition & 0 deletions src/Sim800.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Sim800 : public EventEmitter
Promise<int8_t> *getSignalLevel() const;
Promise<String> *getNetworkName() const;
Promise<String> *getICCID() const;
Promise<SMS *> *getSMS(uint8_t index, bool changeStatus = true) const;
private:
ATConnection *at;
SMSMode smsMode = SMSMode::UNKNOWN;
Expand Down
17 changes: 17 additions & 0 deletions src/Sim800/Events.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "Events.hpp"
#include <string.h>
#include <cstdio>

Sim800IncomingSMSEvent::Sim800IncomingSMSEvent(const char *memory, uint8_t index): index(index)
{
strlcpy(this->memory, memory, sizeof(this->memory));
}

bool Sim800IncomingSMSEvent::parseCMTI(Sim800IncomingSMSEvent *dest, const String &CMTI)
{
int memPos = CMTI.indexOf("+CMTI:");
if (memPos < 0) {
return false;
}
return sscanf(CMTI.c_str() + memPos, "+CMTI: \"%[^\"]\",%hhu", dest->memory, &dest->index) == 2;
}
30 changes: 30 additions & 0 deletions src/Sim800/Events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define SIM800_EVENTS_HPP

#include <Event.hpp>
#include <WString.h>

class Sim800CallReadyEvent : public Event
{
Expand Down Expand Up @@ -33,4 +34,33 @@ class Sim800SimCardNotReadyEvent : public Event
}
};

class Sim800IncomingSMSEvent : public Event
{
private:
char memory[5] = {'\0'};
uint8_t index = 0;
public:
constexpr static event_type_t type = 0xff021004;

static bool parseCMTI(Sim800IncomingSMSEvent *dest, const String &CMTI);
Sim800IncomingSMSEvent() {};
Sim800IncomingSMSEvent(const char *memory, uint8_t index);

event_type_t getType() const
{
return type;
}

inline const char *getMemory() const
{
return memory;
}

inline uint8_t getIndex() const
{
return index;
}

};

#endif
137 changes: 92 additions & 45 deletions src/Sim800/SMS.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "SMS.hpp"

size_t consumeSMSHeaderPart(const char *str, size_t endHeader, size_t &start, size_t &end);
SMS::Status parseStatus(const char *status);

std::vector<SMS *> SMS::parseCMGL(const String &CMGL)
{
size_t len = CMGL.length();
Expand All @@ -10,7 +13,7 @@ std::vector<SMS *> SMS::parseCMGL(const String &CMGL)
{
lastFromIndex = fromIndex;
uint8_t error = 0;
SMS *sms = SMS::parseCMGL(CMGL, fromIndex, error);
SMS *sms = SMS::parse("+CMGL:", CMGL, fromIndex, error);
if (sms != nullptr)
{
list.push_back(sms);
Expand All @@ -19,72 +22,70 @@ std::vector<SMS *> SMS::parseCMGL(const String &CMGL)
return list;
}

SMS *SMS::parseCMGL(const String &CMGL, size_t &fromIndex, uint8_t &error)
SMS *SMS::parse(const String &header, const String &content, size_t &fromIndex, uint8_t &error)
{
auto headerStart = CMGL.indexOf("+CMGL:", fromIndex);
bool isCMGL = header == "+CMGL:";

auto headerStart = content.indexOf(header, fromIndex);
if (headerStart == -1)
{
error = 1;
return nullptr;
}
auto headerEnd = CMGL.indexOf('\r', headerStart + 1);
auto headerEnd = content.indexOf('\r', headerStart + 1);
if (headerEnd == -1)
{
error = 2;
return nullptr;
}
auto endPos = CMGL.indexOf("\r\n+CMGL:", headerEnd + 2);
auto endPos = content.indexOf("\r\n" + header, headerEnd + 2);
if (endPos == -1)
{
endPos = CMGL.length();
}
fromIndex = endPos;
int comma[4];
size_t lastPos = headerStart;
for (uint8_t x = 0; x < 4; x++)
{
comma[x] = CMGL.indexOf(',', lastPos);
if (comma[x] < 0)
{
error = 4;
return nullptr;
}
lastPos = comma[x] + 1;
endPos = content.length();
}
uint8_t id = CMGL.substring(headerStart + 7, comma[0]).toInt();

SMS::Status status = SMS::Status::INBOX_UNREAD;
const char *statuses[] = {
"\"REC UNREAD\"",
"\"REC READ\"",
"\"STO SENT\"",
"\"STO UNSENT\""};
fromIndex = headerStart + header.length() + 1;
bool isText = endPos - headerEnd > 2;

for (uint8_t x = 0; x < 4; x++)
{
if (!isText) {

if (memcmp(CMGL.c_str() + comma[0] + 1, statuses[x], strlen(statuses[x]) - 1) == 0)
{
status = (SMS::Status)x;
break;
}
return nullptr;
}

if (endPos - headerEnd > 2)
{
String peer = CMGL.substring(comma[1] + 1, comma[2]);
if (peer.charAt(0) == '"')
{
peer.remove(0, 1);
SMS::Status status = SMS::Status::INBOX_UNREAD;
uint8_t id = 0;
String peer;

for (uint8_t x = 0; x < 3; x++) {
size_t start = fromIndex;
size_t length = consumeSMSHeaderPart(content.c_str(), headerEnd, start, fromIndex);
if (start == fromIndex) {
error = 3;
return nullptr;
}
const size_t lastIndex = peer.length() - 1;
if (peer.charAt(lastIndex) == '"')
{
peer.remove(lastIndex, 1);
auto part = content.substring(start, start + length);
if (isCMGL) {
switch (x) {
case 0: id = part.toInt(); break;
case 1: status = parseStatus(part.c_str()); break;
case 2: peer = std::move(part); break;
}
} else {
switch (x) {
case 0: status = parseStatus(part.c_str()); break;
case 1: peer = std::move(part); break;
}
}
return new TextSMS(id, status, peer.c_str(), CMGL.substring(headerEnd + 2, endPos).c_str());
}
return nullptr;
fromIndex = endPos;
return new TextSMS(id, status, peer.c_str(), content.substring(headerEnd + 2, endPos).c_str());
}

SMS *SMS::parseCMGR(const String &CMGR)
{
size_t fromIndex = 0;
uint8_t error = 0;
return SMS::parse("+CMGR:", CMGR, fromIndex, error);
}

TextSMS::TextSMS(TextSMS &&other): SMS(other.id, other.status)
Expand Down Expand Up @@ -145,3 +146,49 @@ TextSMS &TextSMS::operator = (TextSMS &&other) {

return *this;
}

size_t consumeSMSHeaderPart(const char *str, size_t endHeader, size_t &start, size_t &end)
{
if (start >= endHeader) {
return 0;
}
bool inValue = false;
size_t length = 0;
for (end = start; end < endHeader; end++) {
char ch = str[end];
if (!inValue) {
if (isspace(ch)) {
start++;
} else if (ch == '"') {
inValue = true;
start++;
} else if (ch == ',') {
end++;
break;
} else {
length++;
}
} else {
if (ch == '"') {
inValue = false;
} else {
length++;
}
}
}
return length;
}

SMS::Status parseStatus(const char *status)
{
const char *statuses[] = {"REC UNREAD", "REC READ", "STO SENT", "STO UNSENT"};
for (uint8_t x = 0; x < 4; x++)
{
if (strcmp(status, statuses[x]) == 0)
{
return (SMS::Status)x;
}
}

return SMS::Status::INBOX_UNREAD;
}
13 changes: 12 additions & 1 deletion src/Sim800/SMS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class SMS

public:
static std::vector<SMS *> parseCMGL(const String &CMGL);
static SMS *parseCMGL(const String &CMGL, size_t &fromIndex, uint8_t &error);
static SMS *parse(const String &header, const String &content, size_t &fromIndex, uint8_t &error);
static SMS *parseCMGR(const String &CMGR);

SMS(uint8_t id, Status status) : id(id), status(status){};
virtual ~SMS()
Expand All @@ -38,9 +39,19 @@ class SMS
return status;
}

inline void setStatus(Status status)
{
this->status = status;
}

inline uint8_t getId() const {
return id;
}

inline void setId(uint8_t id)
{
this->id = id;
}
};

class TextSMS : public SMS
Expand Down

0 comments on commit c3ee176

Please sign in to comment.