vshymanskyy / TinyGSM

A small Arduino library for GSM modules, that just works
GNU Lesser General Public License v3.0
1.93k stars 715 forks source link

[A6] trying to implement read sms #115

Open axwell opened 6 years ago

axwell commented 6 years ago

Hello, i'm trying to implement sms reading in A6 by fetching SMS locations of unread sms with command "+CMGL=REC UNREAD"

Here is my code: sendAT(GF("+CSCS=UCS2")); waitResponse();

sendAT(GF("+CMGF=1")); waitResponse();

sendAT(GF("+CNMI=1,0")); waitResponse();

sendAT(GF("+CMGL="), GF("REC"), GF(" "), GF("UNREAD")); if(waitResponse(GF(GSM_NL "+CMGL:"), GF("OK"))) { data = stream.readString(); Serial.print("message: "); Serial.println(data); }

The issue is that i receive only garbage data and i don't know why. Library works just fine otherwise.

Example of received data:

response

Serial relay works just fine. Response should be like this: https://www.diafaan.com/sms-tutorials/gsm-modem-tutorial/at-cmgl-text-mode/ Can someone help me ? I'm stuck.

shivsey commented 6 years ago

Did you manage to read a valid SMS? Im interested in doing the same with an A7,

axwell commented 6 years ago

@shivsey yes Add this two methods.

int getUnreadSMSLocs(int* buf)
{
        String data;

        int index, occurrences = 0;

        sendAT(GF("+CMGL=\"REC UNREAD\""));
        if(waitResponse(5000L, GF("+CMGL:"), GFP(GSM_OK), GFP(GSM_ERROR))) {
                do {
                        data = stream.readStringUntil('\n');
                        int pos = data.indexOf("REC UNREAD");
                        if (pos > 0) {
                                index = data.substring(0, pos - 1).toInt();
                                buf[occurrences] = index;
                                occurrences++;
                        }
                } while (waitResponse() == 1);
        }
        return occurrences;
}

SMSmessage readSMS(uint8_t i)
{
        char message[300];
        char number[50];
        char date[50];
        char type[10];

        String head;
        String body;

        SMSmessage sms = (const struct SMSmessage) {
                "", "", ""
        };
        sendAT(GF("+CMGR="), i);

        if (waitResponse(10000L, GF(GSM_NL "+CMGR:"))) {

                head = stream.readStringUntil('\n');
                body = stream.readStringUntil('\n');

                sscanf(head.c_str(), "\"REC %s\",\"%s\",,\"%s\"\r\n", type, number, date);
                sms.number  = String(number);
                sms.date    = String(date);

                body.toCharArray(message, body.length());
                sms.message = message;
        }
        return sms;
}

Add struct at the top next to enum things

struct SMSmessage {
        String number;
        String date;
        String message;
};

Red messages like this in the loop

unreadSMSNum = modem.getUnreadSMSLocs(unreadSMSLocs);

                for (int i = 0; i < unreadSMSNum; i++) {
                        Serial.print("New message at index: ");
                        // Serial.println(unreadSMSLocs[i], DEC);

                        sms = modem.readSMS(i);
                }

Add method:

void prefSettings()
{
        sendAT(GF("+CPMS=ME,ME,ME"));
        waitResponse();

        sendAT(GF("+CMGF=1"));
        waitResponse();

        sendAT(GF("+CNMI=1,0"));
        waitResponse();

        sendAT(GF("+CSCS=\"GSM\""));
        waitResponse();
}

Initialize it after you have a valid operator. Initialize serial connection with a bigger buffer, like 512

I hope you understand i did not have time to make a merge request.

shivsey commented 6 years ago

Thanks, got it to compile no problem, still waiting to receive the module but the code looks pretty straight forward. If you have anymore A6/A7 specific code let me know.

DmitriVLK commented 6 years ago

First, my question: I get the ### Unhandled message when several SMSs are being processed. Maybe someone can look up to this problem and propose a FIX?

Other than that, I added a couple of feautures and tested for the SIM900 chip.

There is a need to delete SMSs that have been read. Otherwise the SIM card can't hold more than X SMSs (my SIM card can hold up to 50 SMS and than I stops receiving any new messages)

So I added the followin code:

First, I modified the structs. I use these ones:

struct SMSmessage {
        String number;
        String message;
};

struct SMSList {
    int* ids;
        int count;
};

To delete a(a list of) message(s) I do the following:

void deleteAllReadSMS()
{
    SMSList readSMS = getSMSs(true);
    for(int i=0; i< readSMS.count; i++) {
        deleteSMS(readSMS.ids[i]);
    }
}
void deleteSMS(uint8_t i)
{
    sendAT(GF("+CMGD="), i);
    waitResponse(1000L, GFP(GSM_OK), GFP(GSM_ERROR));
}

And to read incoming SMS's IDs on the SIM card and count them I use:

/**
*   Retreive all the SMSs that are read (if boolean set to true) or unread (if boolean
*   set to false)
*/
SMSList getSMSs(bool isRead)
{       
    SMSList readSMS = (const struct SMSList) {
        new int[0], 0
    };

        String data;

        int index, occurrences = 0;
    int* indexes = new int[occurrences];

        sendAT(GF("+CMGL=\"REC "), isRead?GF("READ"):GF("UNREAD"), GF("\""));
        if(waitResponse(5000L, GF("+CMGL:"), GFP(GSM_OK), GFP(GSM_ERROR))) {
                do {
                        data = stream.readStringUntil('\n');
                        int pos = data.indexOf("REC " + isRead?"READ":"UNREAD");
                        if (pos > 0) {
                                index = data.substring(0, pos - 1).toInt();
                // Resize to a +1 size
                int* indexesT = new int[occurrences + 1];
                for(int j=0; j < occurrences;j++){
                    indexesT[j] = indexes[j];
                }

                // Free memory
                delete indexes;

                indexes = indexesT;

                                indexes[occurrences] = index;
                                occurrences++;
                // And skip until the end of text message
                streamSkipUntil('\n');
                        }
                } while (waitResponse() == 1);
        }
    readSMS.ids = indexes;
    readSMS.count = occurrences;
        return readSMS;
}

And finally, to read an individual SMS I do:

SMSmessage readSMS(uint8_t i)
{
        char message[300];
        char number[50];
        char date[50];
        char type[10];

        String head;
        String body;

        SMSmessage sms = (const struct SMSmessage) {
                "", ""
        };
        sendAT(GF("+CMGR="), i);

        if (waitResponse(10000L, GF(GSM_NL "+CMGR:"))) {

                head = stream.readStringUntil('\n');
                body = stream.readStringUntil('\n');

        int counter = 0;
        int var = 0;

        for(int i=0; i< head.length(); i++)
        {
            // There is a comma after comma or Quotes sign after comma
            if(head.charAt(i) == ',')
            {
                    // Skip , and " sign. I know what I'm doing!
                i++; i++;
                while(head.charAt(i) != ',') {
                    number[counter] = head.charAt(i);
                    // I know what I'm doing!
                    counter++;
                    i++;
                }
                number[counter-1] = '\0';
            }
        }

        sms.number  = String(number);

                body.toCharArray(message, body.length());
                sms.message = message;
        }
        return sms;
}

I get "### Unhandled" messages when several SMSs arrive at the same time.

For example: ### Unhandled: +CMGL: 3,"REC READ","+XXXXXXXXXXX","My Number","18/02/22,20:47:02+04"

Maybe someone can fixthis issue.

Otherwise, if only 1 sms is received at a time, it's a bit slow but looks OK.

jeancaffou commented 5 years ago

@DmitriVLK

First, I modified the structs. I use these ones:

Stay off the heap!

Your code is producing memory leaks.