Added HTTP API to C027_Support library.
Fork of C027_Support by
Revision 136:95ae93a46ae5, committed 2016-01-21
- Comitter:
- fdilenarda
- Date:
- Thu Jan 21 14:59:31 2016 +0000
- Parent:
- 135:2fbd5723e063
- Parent:
- 134:307c15ce18e8
- Commit message:
- Merge between HTTP API and features for connection manager.
Changed in this revision
MDM.cpp | Show annotated file Show diff for this revision Revisions of this file |
MDM.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 2fbd5723e063 -r 95ae93a46ae5 MDM.cpp --- a/MDM.cpp Tue Jan 12 08:37:29 2016 +0000 +++ b/MDM.cpp Thu Jan 21 14:59:31 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;
diff -r 2fbd5723e063 -r 95ae93a46ae5 MDM.h --- a/MDM.h Tue Jan 12 08:37:29 2016 +0000 +++ b/MDM.h Thu Jan 21 14:59:31 2016 +0000 @@ -274,7 +274,83 @@ \return true if successfully, false otherwise */ bool socketFree(int socket); - + + // ---------------------------------------------------------------- + // HTTP + // ---------------------------------------------------------------- + + //! Type of HTTP Operational Codes (reference to HTTP control +UHTTP) + typedef enum { HTTP_IP_ADDRESS, HTTP_SERVER_NAME, HTTP_USER_NAME, HTTP_PASSWORD, \ + HTTP_AUTH_TYPE, HTTP_PORT, HTTP_SECURE } HttpOpCode; + + //! Type of HTTP Commands (reference to HTTP command +UHTTPC) + typedef enum { HTTP_HEAD, HTTP_GET, HTTP_DELETE, HTTP_PUT, \ + HTTP_POST_FILE, HTTP_POST_DATA } HttpCmd; + + //! HTTP Profile error return codes + #define HTTP_PROF_ERROR -1 + + /** find HTTP profile + \return true if successfully, false otherwise + */ + int httpFindProfile(); + + /** get the number of bytes pending for reading for this HTTP profile + \param profile the HTTP profile handle + \param timeout_ms -1 blocking, else non blocking timeout in ms + \return 0 if successful or SOCKET_ERROR on failure + */ + bool httpSetBlocking(int profile, int timeout_ms); + + /** set the HTTP profile for commands management + \param profile the HTTP profile handle + \return true if successfully, false otherwise + */ + bool httpSetProfileForCmdMng(int profile); + + /** free the HTTP profile + \param profile the HTTP profile handle + \return true if successfully, false otherwise + */ + bool httpFreeProfile(int profile); + + /** reset HTTP profile + \param httpProfile the HTTP profile to be reset + \return true if successfully, false otherwise + */ + bool httpResetProfile(int httpProfile); + + /** set HTTP parameters + \param httpProfile the HTTP profile identifier + \param httpOpCode the HTTP operation code + \param httpInPar the HTTP input parameter + \return true if successfully, false otherwise + */ + bool httpSetPar(int httpProfile, HttpOpCode httpOpCode, const char * httpInPar); + + /** HTTP commands management + \param httpProfile the HTTP profile identifier + \param httpCmdCode the HTTP command code + \param httpPath the path of HTTP server resource + \param httpOut the filename where the HTTP server response will be stored + \param httpIn the input data (filename or string) to be sent + to the HTTP server with the command request + \param httpContentType the HTTP Content-Type identifier + \param httpCustomPar the parameter for an user defined HTTP Content-Type + \param buf the buffer to read into + \param len the size of the buffer to read into + \return true if successfully, false otherwise + */ + bool httpCommand(int httpProfile, HttpCmd httpCmdCode, const char* httpPath, \ + const char* httpOut, const char* httpIn, int httpContentType, \ + const char* httpCustomPar, char* buf, int len); + + /** get HTTP commands + \param httpCmdCode the HTTP command code (reference also the enum format) + \return HTTP command in string format + */ + const char* getHTTPcmd(int httpCmdCode); + // ---------------------------------------------------------------- // SMS Short Message Service // ---------------------------------------------------------------- @@ -340,13 +416,29 @@ */ int writeFile(const char* filename, const char* buf, int len); - /** REad a file from the local file system + /** Read a file from the local file system \param filename the name of the file \param buf a buffer to hold the data \param len the size to read \return the number of bytes read */ int readFile(const char* filename, char* buf, int len); + + /** Read a file from the local file system + (the file size is greater than MAX_SIZE bytes) + \param filename the name of the file + \param buf a buffer to hold the data + \param len the size to read + \return the number of bytes read + */ + int readFileNew(const char* filename, char* buf, int len); + + /** Retrieve information about the dimension of a file from the local FFS + \param filename the name of the file + \return the file dimension in number of bytes + */ + int infoFile(const char* filename); + // ---------------------------------------------------------------- // Cell Locate // ---------------------------------------------------------------- @@ -626,6 +718,8 @@ typedef struct { const char* filename; char* buf; int sz; int len; } URDFILEparam; static int _cbUDELFILE(int type, const char* buf, int len, void*); static int _cbURDFILE(int type, const char* buf, int len, URDFILEparam* param); + static int _cbURDBLOCK(int type, const char* buf, int len, char* out); + static int _cbULSTFILE(int type, const char* buf, int len, int* infoFile); // variables DevStatus _dev; //!< collected device information NetStatus _net; //!< collected network information @@ -637,6 +731,16 @@ // LISA-U and SARA-G have 7 sockets SockCtrl _sockets[12]; int _findSocket(int handle = SOCKET_ERROR/* = CREATE*/); + // management structure for HTTP profiles + // it's possible to have up to 4 different HTTP profiles (LISA-C200, LISA-U200 and SARA-G350) having: + // param handle the current HTTP profile is in handling state or not (default value is HTTP_ERROR) + // param timeout_ms the timeout for the current HTTP command + // param pending the status for the current HTTP command (in processing state or not) + // param cmd the code for the current HTTP command + // param result the result for the current HTTP command once processed + typedef struct { int handle; int timeout_ms; bool pending; int cmd; int result; } HttpProfCtrl; + HttpProfCtrl _httpProfiles[4]; + int _findProfile(int handle = HTTP_PROF_ERROR/* = CREATE*/); static MDMParser* inst; bool _init; #ifdef TARGET_UBLOX_C027