support library for C027 helper functions for Buffer Pipes, Buffered Serial Port (rtos capable) and GPS parsing. It includes modem APIs for USSD, SMS and Sockets.

Dependents:   HTTPClient_Cellular_HelloWorld Cellular_HelloMQTT MbedSmartRestMain Car_Bon_car_module ... more

This library is intended to be used with u-blox products such as the C027 or a shield with u-blox cellular and GPS modules like the cellular and positioning shield from Embedded Artist.

For 2G/GSM and 3G/UMTS you need to:

  • have a SIM card and know its PIN number
  • need to know you network operators APN setting These setting should be passed to the connect or init and join functions. You can also extend the APN database in MDMAPN.h.

For CDMA products you need to make sure that you have provisioned and activated the modem with either Sprint or Verizon.

Revision:
135:cbccf4052d45
Parent:
134:2fbd5723e063
Child:
136:8dc8f48275fc
--- a/MDM.cpp	Tue Jan 12 08:37:29 2016 +0000
+++ b/MDM.cpp	Thu Jan 21 15:59:42 2016 +0000
@@ -13,6 +13,10 @@
 #define ISSOCKET(s)     (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR))
 //! check for timeout
 #define TIMEOUT(t, ms)  ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 
+// num HTTP profiles
+#define NUMPROFILES      (sizeof(_httpProfiles)/sizeof(*_httpProfiles))
+//! test if it is an HTTP profile is ok to use
+#define ISPROFILE(p)     (((p) >= 0) && ((p) < NUMPROFILES) && (_httpProfiles[p].handle != HTTP_PROF_ERROR))
 //! registration ok check helper
 #define REG_OK(r)       ((r == REG_HOME) || (r == REG_ROAMING)) 
 //! registration done check helper (no need to poll further)
@@ -103,6 +107,9 @@
     memset(_sockets, 0, sizeof(_sockets));
     for (int socket = 0; socket < NUMSOCKETS; socket ++)
         _sockets[socket].handle = SOCKET_ERROR;
+    memset(_httpProfiles, 0, sizeof(_httpProfiles));
+    for (int profile = 0; profile < NUMPROFILES; profile ++)
+        _httpProfiles[profile].handle = HTTP_PROF_ERROR;
 #ifdef MDM_DEBUG
     _debugLevel = 1;
     _debugTime.start();
@@ -196,8 +203,13 @@
                     _loc.time.tm_yday=0;
                     _loc.validData = true;
                     TRACE("Parsed UULOC position\r\n");
-               }
-               if (_dev.dev == DEV_LISA_C2) {
+                // +UHTTPCR: <profile_id>,<op_code>,<param_val>
+                } else if ((sscanf(cmd, "UUHTTPCR: %d,%d,%d", &a, &b, &c) == 3)) {
+                    _httpProfiles[a].cmd = b;          //command
+                    _httpProfiles[a].result = c;       //result
+                    TRACE("%s for profile %d: result code is %d\r\n", getHTTPcmd(b), a, c);
+                }
+                if (_dev.dev == DEV_LISA_C2) {
                     // CDMA Specific -------------------------------------------
                     // +CREG: <n><SID>,<NID>,<stat>
                     if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
@@ -1315,6 +1327,301 @@
 }
 
 // ----------------------------------------------------------------
+// HTTP
+
+int MDMParser::httpFindProfile()
+{
+    int profile = HTTP_PROF_ERROR;  //default value
+    LOCK();
+    // find a free HTTP profile 
+    profile = _findProfile();
+    TRACE("httpFindProfile: profile is %d\r\n", profile);
+    if (profile != HTTP_PROF_ERROR) {
+        _httpProfiles[profile].handle     = 1;
+        _httpProfiles[profile].timeout_ms = TIMEOUT_BLOCKING;
+        _httpProfiles[profile].pending    = false;
+        _httpProfiles[profile].cmd        = -1;
+        _httpProfiles[profile].result     = -1;
+    }
+    UNLOCK();
+    return profile;
+}
+
+int MDMParser::_findProfile(int handle) {
+    for (int profile = 0; profile < NUMPROFILES; profile++) {
+        if (_httpProfiles[profile].handle == handle)
+            return profile;
+    }
+    return HTTP_PROF_ERROR;
+}
+
+bool MDMParser::httpSetBlocking(int profile, int timeout_ms)
+{
+    bool ok = false;
+    LOCK();
+    TRACE("httpSetBlocking(%d,%d)\r\n", profile, timeout_ms);
+    if (ISPROFILE(profile)) {
+        _httpProfiles[profile].timeout_ms = timeout_ms;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::httpSetProfileForCmdMng(int profile)
+{
+    bool ok = false;
+    LOCK();
+    TRACE("httpSetProfileForCmdMng(%d)\r\n", profile);
+    if (ISPROFILE(profile)) {
+        _httpProfiles[profile].pending = true;
+        _httpProfiles[profile].result = -1;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::httpFreeProfile(int profile)
+{
+    bool ok = true;
+    LOCK();
+    if (ISPROFILE(profile)) {
+        TRACE("httpFreeProfile(%d)\r\n", profile);
+        _httpProfiles[profile].handle     = HTTP_PROF_ERROR;
+        _httpProfiles[profile].timeout_ms = TIMEOUT_BLOCKING;
+        _httpProfiles[profile].pending    = false;
+        _httpProfiles[profile].cmd        = -1;
+        _httpProfiles[profile].result     = -1;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::httpResetProfile(int httpProfile)
+{
+    bool ok = false;
+    
+    LOCK();
+    TRACE("httpResetProfile(%d)\r\n", httpProfile);
+    sendFormated("AT+UHTTP=%d\r\n", httpProfile);
+    if (RESP_OK == waitFinalResp())
+        ok = true;
+    UNLOCK();
+    
+    return ok;
+}
+
+bool MDMParser::httpSetPar(int httpProfile, HttpOpCode httpOpCode, const char * httpInPar)
+{
+    bool ok = false;
+    IP ip = NOIP;
+    int httpInParNum = 0;
+    
+    LOCK();
+    TRACE("httpSetPar(%d,%d,\"%s\")\r\n", httpProfile, httpOpCode, httpInPar);
+    switch(httpOpCode){
+        case HTTP_IP_ADDRESS:   //0
+            ip = gethostbyname(httpInPar);
+            if (ip == NOIP)
+                return false;
+            
+            sendFormated("AT+UHTTP=%d,%d,\"" IPSTR "\"\r\n", httpProfile, httpOpCode, IPNUM(ip));
+            if (RESP_OK == waitFinalResp())
+                ok = true;
+            break;
+            
+        case HTTP_SERVER_NAME:  //1
+        case HTTP_USER_NAME:    //2
+        case HTTP_PASSWORD:     //3
+            sendFormated("AT+UHTTP=%d,%d,\"%s\"\r\n", httpProfile, httpOpCode, httpInPar);
+            if (RESP_OK == waitFinalResp())
+                ok = true;
+            break;
+        
+        case HTTP_AUTH_TYPE:    //4    
+        case HTTP_PORT:         //5
+            httpInParNum = atoi(httpInPar);
+            sendFormated("AT+UHTTP=%d,%d,%d\r\n", httpProfile, httpOpCode, httpInParNum); 
+            if (RESP_OK == waitFinalResp())
+                ok = true;
+            break;
+            
+        case HTTP_SECURE:       //6
+            if(_dev.dev != DEV_LISA_C2)
+            {
+                httpInParNum = atoi(httpInPar);
+                sendFormated("AT+UHTTP=%d,%d,%d\r\n", httpProfile, httpOpCode, httpInParNum); 
+                if (RESP_OK == waitFinalResp())
+                    ok = true;
+            } else {
+                TRACE("httpSetPar: HTTP secure option not supported by module\r\n");
+                ok = false;
+            }
+            break;
+            
+        default:
+            TRACE("httpSetPar: unknown httpOpCode %s\r\n", httpOpCode);
+            ok = false; 
+            break;   
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::httpCommand(int httpProfile, HttpCmd httpCmdCode, const char* httpPath, const char* httpOut, \
+                            const char* httpIn, int httpContentType, const char* httpCustomPar, char* buf, int len)
+{   
+    bool ok = false;
+#ifdef MDM_DEBUG
+    memset(buf, '\0', len);
+#endif
+    LOCK();
+    TRACE("%s\r\n", getHTTPcmd(httpCmdCode));
+    switch (httpCmdCode) 
+    {   
+        case HTTP_HEAD:
+            sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_HEAD, httpPath, httpOut);
+            break;
+            
+        case HTTP_GET:
+            sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_GET, httpPath, httpOut);
+            break;
+            
+        case HTTP_DELETE:
+            sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\"\r\n", httpProfile, HTTP_DELETE, httpPath, httpOut);
+            break;
+            
+        case HTTP_PUT:
+            //in this case the parameter httpIn is a filename
+            sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\"\r\n", httpProfile, HTTP_PUT, httpPath, httpOut, httpIn);
+            break;
+            
+        case HTTP_POST_FILE:
+            //in this case the parameter httpIn is a filename
+            if(_dev.dev != DEV_LISA_C2)
+            {
+                if(httpContentType != 6)
+                    sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
+                                  httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType);
+                else
+                    sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%d\r\n", \
+                                  httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType, httpCustomPar);
+            }
+            else{
+                if((httpContentType != 5) && (httpContentType != 6) && (httpCustomPar == NULL))
+                {
+                    //parameters values consistent with the AT commands specs of LISA-C200
+                    //(in particular httpCustomPar has to be not defined)
+                    sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
+                                  httpProfile, HTTP_POST_FILE, httpPath, httpOut, httpIn, httpContentType);
+                } else {
+                    TRACE("httpCommand: command not supported by module");
+                    return ok;  //error
+                }
+            }
+            break;
+            
+        case HTTP_POST_DATA:
+            //in this case the parameter httpIn is a string containing data
+            if(_dev.dev != DEV_LISA_C2)
+            {
+                if(httpContentType != 6)
+                    sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
+                                  httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType);
+                else
+                    sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%d\r\n", \
+                                  httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType, httpCustomPar);
+            } else {
+                if((httpContentType != 5) && (httpContentType != 6) && (httpCustomPar == NULL))
+                {
+                    //parameters values consistent with the AT commands specs of LISA-C200
+                    //(in particular httpCustomPar has to be not defined)
+                    sendFormated("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d\r\n", \
+                                  httpProfile, HTTP_POST_DATA, httpPath, httpOut, httpIn, httpContentType);
+                } else {
+                    TRACE("httpCommand: command not supported by module");
+                    return ok;  //error
+                }
+            }    
+            break;
+            
+        default:
+            TRACE("HTTP command not recognized\r\n");
+            return ok;  //error
+    }
+    
+    if (RESP_OK == waitFinalResp())
+    {
+        Timer timer;
+        timer.start();
+        httpSetProfileForCmdMng(httpProfile);
+        while (_httpProfiles[httpProfile].pending)  //waiting for unsolicited
+        {     
+            ok = false;  //reset variable  
+            if(_httpProfiles[httpProfile].result != -1)
+            {    
+                //received unsolicited: starting its analysis 
+                _httpProfiles[httpProfile].pending = false;   
+                if(_httpProfiles[httpProfile].result == 1)
+                {
+                    //HTTP command successfully executed
+                    if(_dev.dev != DEV_LISA_C2)
+                    {
+                        TRACE("httpCommand: reading files with a dimension " \
+                              "also greater than MAX_SIZE bytes\r\n");
+                        if(readFileNew(httpOut,buf,len) >=0 )
+                            ok = true;
+                    } else {
+                        TRACE("httpCommand: reading files with a dimension " \
+                              "less than MAX_SIZE bytes, otherwise error\r\n");
+                        if(readFile(httpOut,buf,len) >=0 )
+                            ok = true;
+                    }
+                } else {
+                    //HTTP command not successfully executed
+                    ok = false;
+                }
+            } else if (!TIMEOUT(timer, _httpProfiles[httpProfile].timeout_ms)) {
+                ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
+            } else  {
+                //not received unsolicited and expired timer
+                TRACE("httpCommand: not received unsolicited and expired timer\r\n");
+                ok = false;
+            }
+            if (!ok) {
+                TRACE("%s: ERROR\r\n", getHTTPcmd(httpCmdCode));
+                _httpProfiles[httpProfile].pending = false;  //no more while loops
+            }
+        }
+    }
+    UNLOCK();
+    return ok;
+}
+
+const char* MDMParser::getHTTPcmd(int httpCmdCode) 
+{
+    switch (httpCmdCode) 
+    {
+        case HTTP_HEAD:
+            return "HTTP HEAD command";
+        case HTTP_GET:
+            return "HTTP GET command";
+        case HTTP_DELETE:
+            return "HTTP DELETE command";
+        case HTTP_PUT:
+            return "HTTP PUT command";
+        case HTTP_POST_FILE:
+            return "HTTP POST file command";
+        case HTTP_POST_DATA:
+            return "HTTP POST data command";
+        default:
+            return "HTTP command not recognized";
+   }
+}
+
+// ----------------------------------------------------------------
 
 int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
 { 
@@ -1482,7 +1789,112 @@
     }
     return WAIT;
 }
+
+//The following function is useful for reading files with a dimension greater than MAX_SIZE bytes
+int MDMParser::readFileNew(const char* filename, char* buf, int len)
+{   
+    int countBytes = -1;  //counter for file reading (default value)
+    
+    if(_dev.dev != DEV_LISA_C2)
+    {
+        //retrieve information about the file, in particular its size
+        int filesize = infoFile(filename);
+        TRACE("readFileNew: filename is %s; filesize is %d\r\n", filename, filesize);
+        
+        if (len < filesize)
+            TRACE("readFileNew: WARNING. Buffer dimension is %d bytes," \
+                  "while file size is %d bytes\r\n", len, filesize);
+        
+        if (filesize > 0)
+        {
+#ifdef MDM_DEBUG
+            memset(buf, '\0', len);
+#endif
+            int offset = 0;              //start reading from 0
+            int blockSize = MAX_SIZE;    //still need space for headers and unsolicited commands
+            int bytesToRead = filesize;  //bytes to read 
+            
+            while (bytesToRead)
+            {    
+                bool ok = false;
+                
+                if (bytesToRead < blockSize)
+                    blockSize = bytesToRead;
+                
+                LOCK();
+                if (blockSize > 0) {
+                            
+                    sendFormated("AT+URDBLOCK=\"%s\",%d,%d\r\n", filename, offset, blockSize);
+                    
+                    if (RESP_OK == waitFinalResp(_cbURDBLOCK, buf)) {
+                        bytesToRead -= blockSize;
+                        offset += blockSize;
+                        buf += blockSize;
+                        ok = true;
+                    } else {
+                        //error condition
+                        countBytes = -1;
+                        ok = false;
+                    }
+                }
+                UNLOCK();
+                
+                if (!ok) {
+                    TRACE("readFileNew: ERROR\r\n");
+                    return countBytes;  //in this case countBytes is -1
+                }
+            }
+            
+            countBytes = offset;  //total read bytes
+            return countBytes;
+        }
+    } else {
+        TRACE("httpCommand: command not supported by module"); 
+    }
+    return countBytes;  //it could be 0 or -1 (possible error)    
+}
+
+int MDMParser::_cbURDBLOCK(int type, const char* buf, int len, char* out)
+{   
+    char fileNameRes[48]; 
+    int sizeRes;
+    
+    if ((type == TYPE_PLUS) && out) {
+        if ((sscanf(buf, "\r\n+URDBLOCK: \"%[^\"]\",%d,", fileNameRes, &sizeRes) == 2) &&
+            (buf[len-sizeRes-2] == '\"') && (buf[len-1] == '\"')) {
+            memcpy(out, &buf[len-1-sizeRes], sizeRes);
+        }
+    }
+    
+    return WAIT;
+}
+
+int MDMParser::infoFile(const char* filename)
+{
+    int infoFile = 0;  //default value
+    
+    LOCK();
+    sendFormated("AT+ULSTFILE=2,\"%s\"\r\n", filename);
+    if (RESP_OK != waitFinalResp(_cbULSTFILE, &infoFile))
+        infoFile = -1;  //error condition    
+    UNLOCK();
+    
+    return infoFile;
+}
+
+int MDMParser::_cbULSTFILE(int type, const char* buf, int len, int* infoFile)
+{ 
+    if (infoFile) {
+        if (type == TYPE_PLUS) {
+            if (sscanf(buf, "\r\n+ULSTFILE: %d\r\n", infoFile) == 1) {
+            }
+        }
+    }
+    return WAIT;
+}
+
 // ----------------------------------------------------------------
+
 int MDMParser::cellLocSrvHttp (const char* token, const char* server_1, const char* server_2, int days/* = 14*/, \
         int period/* = 4*/, int resolution/* = 1*/)
 {
@@ -1728,6 +2140,7 @@
             { "\r\n+USORD: %d,%d,\"%c\"",                   TYPE_PLUS       },
             { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"",  TYPE_PLUS       },
             { "\r\n+URDFILE: %s,%d,\"%c\"",                 TYPE_PLUS       },
+            { "\r\n+URDBLOCK: %s,%d,\"%c\"",                TYPE_PLUS       },
         };
         static struct { 
               const char* sta;          const char* end;    int type;