C027 updated to work with latest mBed libraries

Dependents:   Cellular_HelloMQTT UBLOXModemDriver UBLOXMQTTDriver

Fork of C027_Support by u-blox

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;