This class adds HTTP, FTP and CellLocate client support for u-blox modules for the C027 and C030 boards (excepting the C030 N2xx flavour) from mbed 5.5 onwards. The HTTP, FTP and CellLocate operations are all hosted on the module, minimizing RAM consumption in the mbed MCU. It also sub-classes ublox-cellular-driver-gen to bring in SMS, USSD and modem file system support if you need to use these functions at the same time as the cellular interface.

Dependencies:   ublox-at-cellular-interface

Dependents:   example-ublox-at-cellular-interface-ext HelloMQTT ublox_new_driver_test example-ublox-at-cellular-interface-ext ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxATCellularInterfaceExt.cpp Source File

UbloxATCellularInterfaceExt.cpp

00001 /* Copyright (c) 2017 ublox Limited
00002  *
00003  * Licensed under the Apache License, Version 2.0 (the "License");
00004  * you may not use this file except in compliance with the License.
00005  * You may obtain a copy of the License at
00006  *
00007  *     http://www.apache.org/licenses/LICENSE-2.0
00008  *
00009  * Unless required by applicable law or agreed to in writing, software
00010  * distributed under the License is distributed on an "AS IS" BASIS,
00011  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012  * See the License for the specific language governing permissions and
00013  * limitations under the License.
00014  */
00015 
00016 #include "UbloxATCellularInterfaceExt.h"
00017 #include "APN_db.h"
00018 #ifdef FEATURE_COMMON_PAL
00019 #include "mbed_trace.h"
00020 #define TRACE_GROUP "UCAD"
00021 #else
00022 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00023 #define tr_info(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00024 #define tr_warn(format, ...)  debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00025 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__)
00026 #endif
00027 
00028 /**********************************************************************
00029  * PROTECTED METHODS: HTTP
00030  **********************************************************************/
00031 
00032 // Callback for HTTP result code handling.
00033 void UbloxATCellularInterfaceExt::UUHTTPCR_URC()
00034 {
00035     char buf[32];
00036     int a, b, c;
00037 
00038     // Note: not calling _at->recv() from here as we're
00039     // already in an _at->recv()
00040     // +UUHTTPCR: <profile_id>,<op_code>,<param_val>
00041     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00042         if (sscanf(buf, ": %d,%d,%d", &a, &b, &c) == 3) {
00043             _httpProfiles[a].cmd = b;          // Command
00044             _httpProfiles[a].result = c;       // Result
00045             debug_if(_debug_trace_on, "%s on profile %d, result code is %d\n", getHttpCmd((HttpCmd) b), a, c);
00046         }
00047     }
00048 }
00049 
00050 // Find a given profile.  NOTE: LOCK() before calling.
00051 int UbloxATCellularInterfaceExt::findProfile(int modemHandle)
00052 {
00053     for (unsigned int profile = 0; profile < (sizeof(_httpProfiles)/sizeof(_httpProfiles[0]));
00054          profile++) {
00055         if (_httpProfiles[profile].modemHandle == modemHandle) {
00056             return profile;
00057         }
00058     }
00059 
00060     return HTTP_PROF_UNUSED;
00061 }
00062 
00063 // Return a string representing an HTTP AT command.
00064 const char *UbloxATCellularInterfaceExt::getHttpCmd(HttpCmd httpCmd)
00065 {
00066     const char * str = "HTTP command not recognised";
00067 
00068     switch (httpCmd) {
00069         case HTTP_HEAD:
00070             str = "HTTP HEAD command";
00071             break;
00072         case HTTP_GET:
00073             str = "HTTP GET command";
00074             break;
00075         case HTTP_DELETE:
00076             str = "HTTP DELETE command";
00077             break;
00078         case HTTP_PUT:
00079             str = "HTTP PUT command";
00080             break;
00081         case HTTP_POST_FILE:
00082             str = "HTTP POST file command";
00083             break;
00084         case HTTP_POST_DATA:
00085             str = "HTTP POST data command";
00086             break;
00087         default:
00088             break;
00089     }
00090 
00091     return str;
00092 }
00093 
00094 /**********************************************************************
00095  * PROTECTED METHODS: FTP
00096  **********************************************************************/
00097 
00098 // Callback for FTP result code handling.
00099 void UbloxATCellularInterfaceExt::UUFTPCR_URC()
00100 {
00101     char buf[64];
00102     char md5[32];
00103 
00104     // Note: not calling _at->recv() from here as we're
00105     // already in an _at->recv()
00106     // +UUFTPCR: <op_code>,<ftp_result>[,<md5_sum>]
00107     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00108         if (sscanf(buf, ": %d,%d,%32[^\n]\n", &_lastFtpOpCodeResult, &_lastFtpResult, md5) == 3) {
00109             // Store the MD5 sum if we can
00110             if ((_ftpBuf != NULL) && (_ftpBufLen >= 32)) {
00111                 memcpy (_ftpBuf, md5, 32);
00112                 if (_ftpBufLen == 33) {
00113                     *(buf + 32) = 0; // Add a terminator if there's room
00114                 }
00115             }
00116         }
00117         debug_if(_debug_trace_on, "%s result code is %d\n",
00118                  getFtpCmd((FtpCmd) _lastFtpOpCodeResult), _lastFtpResult);
00119     }
00120 }
00121 
00122 // Callback for FTP data handling.
00123 void UbloxATCellularInterfaceExt::UUFTPCD_URC()
00124 {
00125     char buf[32];
00126     char *ftpBufPtr = _ftpBuf;
00127     int ftpDataLen;
00128 
00129     // Note: not calling _at->recv() from here as we're
00130     // already in an _at->recv()
00131     // +UUFTPCD: <op_code>,<ftp_data_len>,<ftp_data_in_quotes>
00132     if (read_at_to_char(buf, sizeof(buf), '\"') > 0) {
00133         if (sscanf(buf, ": %d,%d,\"", &_lastFtpOpCodeData, &ftpDataLen) == 2) {
00134             if ((ftpBufPtr != NULL) && (_ftpBufLen > 0)) {
00135                 if (ftpDataLen + 1 > _ftpBufLen) { // +1 for terminator
00136                     ftpDataLen = _ftpBufLen - 1;
00137                 }
00138                 ftpBufPtr += _at->read(ftpBufPtr, ftpDataLen);
00139                 *ftpBufPtr = 0; // Add terminator
00140             }
00141         }
00142     }
00143 }
00144 
00145 // Return a string representing an FTP AT command.
00146 const char *UbloxATCellularInterfaceExt::getFtpCmd(FtpCmd ftpCmd)
00147 {
00148     const char * str = "FTP command not recognised";
00149 
00150     switch (ftpCmd) {
00151         case FTP_LOGOUT:
00152             str = "FTP log out command";
00153             break;
00154         case FTP_LOGIN:
00155             str = "FTP log in command";
00156             break;
00157         case FTP_DELETE_FILE:
00158             str = "FTP delete file command";
00159             break;
00160         case FTP_RENAME_FILE:
00161             str = "FTP rename file command";
00162             break;
00163         case FTP_GET_FILE:
00164             str = "FTP get file command";
00165             break;
00166         case FTP_PUT_FILE:
00167             str = "FTP put file command";
00168             break;
00169         case FTP_CD:
00170             str = "FTP change directory command";
00171             break;
00172         case FTP_MKDIR:
00173             str = "FTP make directory command";
00174             break;
00175         case FTP_RMDIR:
00176             str = "FTP remove directory command";
00177             break;
00178         case FTP_FILE_INFO:
00179             str = "FTP file info command";
00180             break;
00181         case FTP_LS:
00182             str = "FTP directory list command";
00183             break;
00184         case FTP_FOTA_FILE:
00185             str = "FTP FOTA file command";
00186             break;
00187         default:
00188             break;
00189     }
00190 
00191     return str;
00192 }
00193 
00194 /**********************************************************************
00195  * PROTECTED METHODS: Cell Locate
00196  **********************************************************************/
00197 
00198 // Callback for UULOCIND handling.
00199 void UbloxATCellularInterfaceExt::UULOCIND_URC()
00200 {
00201     char buf[32];
00202     int a, b;
00203 
00204     // Note: not calling _at->recv() from here as we're
00205     // already in an _at->recv()
00206     // +UULOCIND: <step>,<result>
00207     if (read_at_to_char(buf, sizeof (buf), '\n') > 0) {
00208         if (sscanf(buf, " %d,%d", &a, &b) == 2) {
00209             switch (a) {
00210                 case 0:
00211                     debug_if(_debug_trace_on, "Network scan start\n");
00212                     break;
00213                 case 1:
00214                     debug_if(_debug_trace_on, "Network scan end\n");
00215                     break;
00216                 case 2:
00217                     debug_if(_debug_trace_on, "Requesting data from server\n");
00218                     break;
00219                 case 3:
00220                     debug_if(_debug_trace_on, "Received data from server\n");
00221                     break;
00222                 case 4:
00223                     debug_if(_debug_trace_on, "Sending feedback to server\n");
00224                     break;
00225                 default:
00226                     debug_if(_debug_trace_on, "Unknown step\n");
00227                     break;
00228             }
00229             switch (b) {
00230                 case 0:
00231                     // No error
00232                     break;
00233                 case 1:
00234                     debug_if(_debug_trace_on, "Wrong URL!\n");
00235                     break;
00236                 case 2:
00237                     debug_if(_debug_trace_on, "HTTP error!\n");
00238                     break;
00239                 case 3:
00240                     debug_if(_debug_trace_on, "Create socket error!\n");
00241                     break;
00242                 case 4:
00243                     debug_if(_debug_trace_on, "Close socket error!\n");
00244                     break;
00245                 case 5:
00246                     debug_if(_debug_trace_on, "Write to socket error!\n");
00247                     break;
00248                 case 6:
00249                     debug_if(_debug_trace_on, "Read from socket error!\n");
00250                     break;
00251                 case 7:
00252                     debug_if(_debug_trace_on, "Connection/DNS error!\n");
00253                     break;
00254                 case 8:
00255                     debug_if(_debug_trace_on, "Authentication token problem!\n");
00256                     break;
00257                 case 9:
00258                     debug_if(_debug_trace_on, "Generic error!\n");
00259                     break;
00260                 case 10:
00261                     debug_if(_debug_trace_on, "User terminated!\n");
00262                     break;
00263                 case 11:
00264                     debug_if(_debug_trace_on, "No data from server!\n");
00265                     break;
00266                 default:
00267                     debug_if(_debug_trace_on, "Unknown result!\n");
00268                     break;
00269             }
00270         }
00271     }
00272 }
00273 
00274 // Callback for UULOC URC handling.
00275 void UbloxATCellularInterfaceExt::UULOC_URC()
00276 {
00277     int a, b;
00278 
00279     // Note: not calling _at->recv() from here as we're
00280     // already in an _at->recv()
00281 
00282     // +UHTTPCR: <profile_id>,<op_code>,<param_val>
00283     if (read_at_to_char(urcBuf, sizeof (urcBuf), '\n') > 0) {
00284         // Response type 1
00285         // +UULOC: <date>,<time>,<lat>,<long>,<alt>,<uncertainty>,<speed>, <direction>,<vertical_acc>,<sensor_used>,<SV_used>,<antenna_status>, <jamming_status>
00286         if (sscanf(urcBuf, " %d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%d,%d,%d,%d,%d,%d,%*d,%*d",
00287                    &_loc[0].time.tm_mday, &_loc[0].time.tm_mon,
00288                    &_loc[0].time.tm_year, &_loc[0].time.tm_hour,
00289                    &_loc[0].time.tm_min, &_loc[0].time.tm_sec,
00290                    &_loc[0].latitude, &_loc[0].longitude, &_loc[0].altitude,
00291                    &_loc[0].uncertainty, &_loc[0].speed, &_loc[0].direction,
00292                    &_loc[0].verticalAcc,
00293                    &b, &_loc[0].svUsed) == 15) {
00294             debug_if(_debug_trace_on, "Position found at index 0\n");
00295             _loc[0].sensor = (b == 0) ? CELL_LAST : (b == 1) ? CELL_GNSS :
00296                              (b == 2) ? CELL_LOCATE : (b == 3) ? CELL_HYBRID : CELL_LAST;
00297             _loc[0].time.tm_year -= 1900;
00298             _loc[0].time.tm_mon -= 1;
00299             _loc[0].time.tm_wday = 0;
00300             _loc[0].time.tm_yday = 0;
00301             _loc[0].validData = true;
00302             // Uncertainty can appear as 4294967, which is
00303             // (2^32 - 1) / 1000, or -1.  Since it is confusing
00304             // for the user to get a large positive number instead
00305             // of 0 -1, set it to -1 in th1s case.
00306             if (_loc[0].uncertainty == 4294967) {
00307                 _loc[0].uncertainty = -1;
00308             }
00309             _locExpPos = 1;
00310             _locRcvPos++;
00311         // Response type 2, sensor used 1
00312         // +UULOC: <sol>,<num>,<sensor_used>,<date>,<time>,<lat>,<long>,<alt>,<uncertainty>,<speed>, <direction>,<vertical_acc>,,<SV_used>,<antenna_status>, <jamming_status>
00313         } else if (sscanf(urcBuf, " %d,%d,%d,%d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%d,%d,%d,%d,%d,%*d,%*d",
00314                    &a, &_locExpPos, &b,
00315                    &_loc[CELL_MAX_HYP - 1].time.tm_mday,
00316                    &_loc[CELL_MAX_HYP - 1].time.tm_mon,
00317                    &_loc[CELL_MAX_HYP - 1].time.tm_year,
00318                    &_loc[CELL_MAX_HYP - 1].time.tm_hour,
00319                    &_loc[CELL_MAX_HYP - 1].time.tm_min,
00320                    &_loc[CELL_MAX_HYP - 1].time.tm_sec,
00321                    &_loc[CELL_MAX_HYP - 1].latitude,
00322                    &_loc[CELL_MAX_HYP - 1].longitude,
00323                    &_loc[CELL_MAX_HYP - 1].altitude,
00324                    &_loc[CELL_MAX_HYP - 1].uncertainty,
00325                    &_loc[CELL_MAX_HYP - 1].speed,
00326                    &_loc[CELL_MAX_HYP - 1].direction,
00327                    &_loc[CELL_MAX_HYP - 1].verticalAcc,
00328                    &_loc[CELL_MAX_HYP - 1].svUsed) == 17) {
00329             if (--a >= 0) {
00330                 debug_if(_debug_trace_on, "Position found at index %d\n", a);
00331 
00332                 memcpy(&_loc[a], &_loc[CELL_MAX_HYP - 1], sizeof(*_loc));
00333 
00334                 _loc[a].sensor = (b == 0) ? CELL_LAST : (b == 1) ? CELL_GNSS :
00335                                  (b == 2) ? CELL_LOCATE : (b == 3) ? CELL_HYBRID : CELL_LAST;
00336                 _loc[a].time.tm_year -= 1900;
00337                 _loc[a].time.tm_mon -= 1;
00338                 _loc[a].time.tm_wday = 0;
00339                 _loc[a].time.tm_yday = 0;
00340                 // Uncertainty can appear as 4294967, which is
00341                 // (2^32 - 1) / 1000, or -1.  Since it is confusing
00342                 // for the user to get a large positive number instead
00343                 // of 0 -1, set it to -1 in th1s case.
00344                 if (_loc[a].uncertainty == 4294967) {
00345                     _loc[a].uncertainty = -1;
00346                 }
00347                 _loc[a].validData = true;
00348                 _locRcvPos++;
00349             }
00350         // Response type 2, sensor used 2
00351         //+UULOC: <sol>,<num>,<sensor_used>,<date>,<time>,<lat>,<long>,<alt>,<lat50>,<long50>,<major50>,<minor50>,<orientation50>,<confidence50>[,<lat95>,<long95>,<major95>,<minor95>,<orientation95>,<confidence95>]
00352         } else if (sscanf(urcBuf, " %d,%d,%d,%d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%*f,%*f,%d,%*d,%*d,%*d",
00353                    &a, &_locExpPos, &b,
00354                    &_loc[CELL_MAX_HYP - 1].time.tm_mday,
00355                    &_loc[CELL_MAX_HYP - 1].time.tm_mon,
00356                    &_loc[CELL_MAX_HYP - 1].time.tm_year,
00357                    &_loc[CELL_MAX_HYP - 1].time.tm_hour,
00358                    &_loc[CELL_MAX_HYP - 1].time.tm_min,
00359                    &_loc[CELL_MAX_HYP - 1].time.tm_sec,
00360                    &_loc[CELL_MAX_HYP - 1].latitude,
00361                    &_loc[CELL_MAX_HYP - 1].longitude,
00362                    &_loc[CELL_MAX_HYP - 1].altitude,
00363                    &_loc[CELL_MAX_HYP - 1].uncertainty) == 13) {
00364             if (--a >= 0) {
00365 
00366                 debug_if(_debug_trace_on, "Position found at index %d\n", a);
00367 
00368                 memcpy(&_loc[a], &_loc[CELL_MAX_HYP - 1], sizeof(*_loc));
00369 
00370                 _loc[a].sensor = (b == 0) ? CELL_LAST : (b == 1) ? CELL_GNSS :
00371                                  (b == 2) ? CELL_LOCATE : (b == 3) ? CELL_HYBRID : CELL_LAST;
00372                 _loc[a].time.tm_year -= 1900;
00373                 _loc[a].time.tm_mon -= 1;
00374                 _loc[a].time.tm_wday = 0;
00375                 _loc[a].time.tm_yday = 0;
00376                 _loc[a].speed = 0;
00377                 _loc[a].direction = 0;
00378                 _loc[a].verticalAcc = 0;
00379                 _loc[a].svUsed = 0;
00380                 // Uncertainty can appear as 4294967, which is
00381                 // (2^32 - 1) / 1000, or -1.  Since it is confusing
00382                 // for the user to get a large positive number instead
00383                 // of 0 -1, set it to -1 in th1s case.
00384                 if (_loc[a].uncertainty == 4294967) {
00385                     _loc[a].uncertainty = -1;
00386                 }
00387                 _loc[a].validData = true;
00388                 _locRcvPos++;
00389             }
00390         // Response type 2, sensor used 0
00391         //+UULOC: <sol>,<num>,<sensor_used>,<date>,<time>,<lat>,<long>,<alt>,<uncertainty>
00392         } else if (sscanf(urcBuf, " %d,%d,%d,%d/%d/%d,%d:%d:%d.%*d,%f,%f,%d,%d",
00393                    &a, &_locExpPos, &b,
00394                    &_loc[CELL_MAX_HYP - 1].time.tm_mday,
00395                    &_loc[CELL_MAX_HYP - 1].time.tm_mon,
00396                    &_loc[CELL_MAX_HYP - 1].time.tm_year,
00397                    &_loc[CELL_MAX_HYP - 1].time.tm_hour,
00398                    &_loc[CELL_MAX_HYP - 1].time.tm_min,
00399                    &_loc[CELL_MAX_HYP - 1].time.tm_sec,
00400                    &_loc[CELL_MAX_HYP - 1].latitude,
00401                    &_loc[CELL_MAX_HYP - 1].longitude,
00402                    &_loc[CELL_MAX_HYP - 1].altitude,
00403                    &_loc[CELL_MAX_HYP - 1].uncertainty) == 13) {
00404             if (--a >= 0) {
00405 
00406                 debug_if(_debug_trace_on, "Position found at index %d\n", a);
00407 
00408                 memcpy(&_loc[a], &_loc[CELL_MAX_HYP - 1], sizeof(*_loc));
00409 
00410                 _loc[a].sensor = (b == 0) ? CELL_LAST : (b == 1) ? CELL_GNSS :
00411                                  (b == 2) ? CELL_LOCATE : (b == 3) ? CELL_HYBRID : CELL_LAST;
00412                 _loc[a].time.tm_year -= 1900;
00413                 _loc[a].time.tm_mon -= 1;
00414                 _loc[a].time.tm_wday = 0;
00415                 _loc[a].time.tm_yday = 0;
00416                 _loc[a].speed = 0;
00417                 _loc[a].direction = 0;
00418                 _loc[a].verticalAcc = 0;
00419                 _loc[a].svUsed = 0;
00420                 // Uncertainty can appear as 4294967, which is
00421                 // (2^32 - 1) / 1000, or -1.  Since it is confusing
00422                 // for the user to get a large positive number instead
00423                 // of 0 -1, set it to -1 in th1s case.
00424                 if (_loc[a].uncertainty == 4294967) {
00425                     _loc[a].uncertainty = -1;
00426                 }
00427                 _loc[a].validData = true;
00428                 _locRcvPos++;
00429             }
00430         }
00431     }
00432 }
00433 
00434 /**********************************************************************
00435  * PUBLIC METHODS: GENERAL
00436  **********************************************************************/
00437 
00438 // Constructor.
00439 UbloxATCellularInterfaceExt::UbloxATCellularInterfaceExt(PinName tx,
00440                                                          PinName rx,
00441                                                          int baud,
00442                                                          bool debugOn,
00443                                                          osPriority priority):
00444                              UbloxATCellularInterface(tx, rx, baud, debugOn, priority)
00445 {
00446     // Zero HTTP stuff
00447     memset(_httpProfiles, 0, sizeof(_httpProfiles));
00448     for (unsigned int profile = 0; profile < sizeof(_httpProfiles) / sizeof(_httpProfiles[0]);
00449          profile++) {
00450         _httpProfiles[profile].modemHandle = HTTP_PROF_UNUSED;
00451     }
00452 
00453     // Zero FTP stuff
00454     _ftpTimeout = TIMEOUT_BLOCKING;
00455     _lastFtpOpCodeResult = FTP_OP_CODE_UNUSED;
00456     _lastFtpResult = 0;
00457     _lastFtpOpCodeData = FTP_OP_CODE_UNUSED;
00458     _ftpBuf = NULL;
00459     _ftpBufLen = 0;
00460     _ftpError.eClass = 0;
00461     _ftpError.eCode = 0;
00462 
00463     // Zero Cell Locate stuff
00464     _locRcvPos = 0;
00465     _locExpPos = 0;
00466 
00467     // URC handler for HTTP
00468     _at->oob("+UUHTTPCR", callback(this, &UbloxATCellularInterfaceExt::UUHTTPCR_URC));
00469 
00470     // URC handlers for FTP
00471     _at->oob("+UUFTPCR", callback(this, &UbloxATCellularInterfaceExt::UUFTPCR_URC));
00472     _at->oob("+UUFTPCD", callback(this, &UbloxATCellularInterfaceExt::UUFTPCD_URC));
00473 
00474     // URC handlers for Cell Locate
00475     _at->oob("+UULOCIND:", callback(this, &UbloxATCellularInterfaceExt::UULOCIND_URC));
00476     _at->oob("+UULOC:", callback(this, &UbloxATCellularInterfaceExt::UULOC_URC));
00477 }
00478 
00479 // Destructor.
00480 UbloxATCellularInterfaceExt::~UbloxATCellularInterfaceExt()
00481 {
00482 }
00483 
00484 /**********************************************************************
00485  * PUBLIC METHODS: HTTP
00486  **********************************************************************/
00487 
00488 // Find a free profile.
00489 int UbloxATCellularInterfaceExt::httpAllocProfile()
00490 {
00491     int profile = HTTP_PROF_UNUSED;
00492     LOCK();
00493 
00494     // Find a free HTTP profile
00495     profile = findProfile();
00496     debug_if(_debug_trace_on, "httpFindProfile: profile is %d\n", profile);
00497 
00498     if (profile != HTTP_PROF_UNUSED) {
00499         _httpProfiles[profile].modemHandle = 1;
00500         _httpProfiles[profile].timeout     = TIMEOUT_BLOCKING;
00501         _httpProfiles[profile].pending     = false;
00502         _httpProfiles[profile].cmd         = -1;
00503         _httpProfiles[profile].result      = -1;
00504     }
00505 
00506     UNLOCK();
00507     return profile;
00508 }
00509 
00510 // Free a profile.
00511 bool UbloxATCellularInterfaceExt::httpFreeProfile(int profile)
00512 {
00513     bool success = false;
00514     LOCK();
00515 
00516     if (IS_PROFILE(profile)) {
00517         debug_if(_debug_trace_on, "httpFreeProfile(%d)\n", profile);
00518         _httpProfiles[profile].modemHandle = HTTP_PROF_UNUSED;
00519         _httpProfiles[profile].timeout     = TIMEOUT_BLOCKING;
00520         _httpProfiles[profile].pending     = false;
00521         _httpProfiles[profile].cmd         = -1;
00522         _httpProfiles[profile].result      = -1;
00523         success = _at->send("AT+UHTTP=%d", profile) && _at->recv("OK");
00524     }
00525 
00526     UNLOCK();
00527     return success;
00528 }
00529 
00530 // Set the blocking/timeout state of a profile.
00531 bool UbloxATCellularInterfaceExt::httpSetTimeout(int profile, int timeout)
00532 {
00533     bool success = false;
00534     LOCK();
00535 
00536     debug_if(_debug_trace_on, "httpSetTimeout(%d, %d)\n", profile, timeout);
00537 
00538     if (IS_PROFILE(profile)) {
00539         _httpProfiles[profile].timeout = timeout;
00540         success = true;
00541     }
00542 
00543     UNLOCK();
00544     return success;
00545 }
00546 
00547 // Set a profile back to defaults.
00548 bool UbloxATCellularInterfaceExt::httpResetProfile(int httpProfile)
00549 {
00550     bool success = false;
00551     LOCK();
00552 
00553     debug_if(_debug_trace_on, "httpResetProfile(%d)\n", httpProfile);
00554     success = _at->send("AT+UHTTP=%d", httpProfile) && _at->recv("OK");
00555 
00556     UNLOCK();
00557     return success;
00558 }
00559 
00560 // Set HTTP parameters.
00561 bool UbloxATCellularInterfaceExt::httpSetPar(int httpProfile,
00562                                              HttpOpCode httpOpCode,
00563                                              const char * httpInPar)
00564 {
00565     bool success = false;
00566     int httpInParNum = 0;
00567     SocketAddress address;
00568 
00569     debug_if(_debug_trace_on, "httpSetPar(%d, %d, \"%s\")\n", httpProfile, httpOpCode, httpInPar);
00570     if (IS_PROFILE(httpProfile)) {
00571         LOCK();
00572 
00573         switch(httpOpCode) {
00574             case HTTP_IP_ADDRESS:   // 0
00575                 if (gethostbyname(httpInPar, &address) == NSAPI_ERROR_OK) {
00576                     success = _at->send("AT+UHTTP=%d,%d,\"%s\"",
00577                                         httpProfile, httpOpCode, address.get_ip_address()) &&
00578                               _at->recv("OK");
00579                 }
00580                 break;
00581             case HTTP_SERVER_NAME:  // 1
00582             case HTTP_USER_NAME:    // 2
00583             case HTTP_PASSWORD:     // 3
00584                 success = _at->send("AT+UHTTP=%d,%d,\"%s\"", httpProfile, httpOpCode, httpInPar) &&
00585                           _at->recv("OK");
00586                 break;
00587 
00588             case HTTP_AUTH_TYPE:    // 4
00589             case HTTP_SERVER_PORT:  // 5
00590                 httpInParNum = atoi(httpInPar);
00591                 success = _at->send("AT+UHTTP=%d,%d,%d", httpProfile, httpOpCode, httpInParNum) &&
00592                           _at->recv("OK");
00593                 break;
00594 
00595             case HTTP_SECURE:       // 6
00596                 httpInParNum = atoi(httpInPar);
00597                 success = _at->send("AT+UHTTP=%d,%d,%d", httpProfile, httpOpCode, httpInParNum) &&
00598                           _at->recv("OK");
00599                 break;
00600 
00601             case HTTP_REQ_HEADER:   //9
00602                 success = _at->send("AT+UHTTP=%d,%d,\"%s\"", httpProfile, httpOpCode, httpInPar) &&
00603                 _at->recv("OK");
00604                 break;
00605 
00606             default:
00607                 debug_if(_debug_trace_on, "httpSetPar: unknown httpOpCode %d\n", httpOpCode);
00608                 break;
00609         }
00610 
00611         UNLOCK();
00612     }
00613 
00614     return success;
00615 }
00616 
00617 // Perform an HTTP command.
00618 UbloxATCellularInterfaceExt::Error * UbloxATCellularInterfaceExt::httpCommand(int httpProfile,
00619                                                                               HttpCmd httpCmd,
00620                                                                               const char *httpPath,
00621                                                                               const char *rspFile,
00622                                                                               const char *sendStr,
00623                                                                               int httpContentType,
00624                                                                               const char *httpCustomPar,
00625                                                                               char *buf, int len, int *read_size)
00626 {
00627     bool atSuccess = false;
00628     bool success = false;
00629     int at_timeout;
00630     char defaultFilename[] = "http_last_response_x";
00631 
00632     debug_if(_debug_trace_on, "%s\n", getHttpCmd(httpCmd));
00633 
00634     if (IS_PROFILE(httpProfile)) {
00635         LOCK();
00636         at_timeout = _at_timeout; // Has to be inside LOCK()s
00637 
00638         if (rspFile == NULL) {
00639             sprintf(defaultFilename + sizeof (defaultFilename) - 2, "%1d", httpProfile);
00640             rspFile = defaultFilename;
00641         }
00642 
00643         switch (httpCmd) {
00644             case HTTP_HEAD:
00645                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00646                                       httpPath, rspFile) &&
00647                             _at->recv("OK");
00648                 break;
00649             case HTTP_GET:
00650                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00651                                       httpPath, rspFile) &&
00652                             _at->recv("OK");
00653                 break;
00654             case HTTP_DELETE:
00655                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00656                                       httpPath, rspFile) &&
00657                             _at->recv("OK");
00658                 break;
00659             case HTTP_PUT:
00660                 // In this case the parameter sendStr is a filename
00661                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\"", httpProfile, httpCmd,
00662                                       httpPath, rspFile, sendStr) &&
00663                             _at->recv("OK");
00664                 break;
00665             case HTTP_POST_FILE:
00666                 // In this case the parameter sendStr is a filename
00667                 if (httpContentType != 6) {
00668                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d",
00669                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00670                                           httpContentType) &&
00671                                 _at->recv("OK");
00672                 } else {
00673                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%s",
00674                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00675                                           httpContentType,
00676                                           httpCustomPar) &&
00677                                 _at->recv("OK");
00678                 }
00679                 break;
00680             case HTTP_POST_DATA:
00681                 // In this case the parameter sendStr is a string containing data
00682                 if (httpContentType != 6) {
00683                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d",
00684                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00685                                           httpContentType) &&
00686                                 _at->recv("OK");
00687                 } else {
00688                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%s",
00689                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00690                                           httpContentType,
00691                                           httpCustomPar) &&
00692                                 _at->recv("OK");
00693                 }
00694                 break;
00695             default:
00696                 debug_if(_debug_trace_on, "HTTP command not recognised\n");
00697                 break;
00698         }
00699 
00700         if (atSuccess) {
00701             Timer timer;
00702             int read_length = 0;
00703 
00704             at_set_timeout(1000);
00705             _httpProfiles[httpProfile].pending = true;
00706             _httpProfiles[httpProfile].result = -1;
00707 
00708             // Waiting for unsolicited result code
00709             timer.start();
00710             while (_httpProfiles[httpProfile].pending) {
00711                 if (_httpProfiles[httpProfile].result != -1) {
00712                     // Received unsolicited: starting its analysis
00713                     _httpProfiles[httpProfile].pending = false;
00714                     if (_httpProfiles[httpProfile].result == 1) {
00715                         // Leave a short delay to make sure the file has been written
00716                         ThisThread::sleep_for(100);
00717                         // HTTP command successfully executed
00718                         read_length = readFile(rspFile, buf, len);
00719 
00720                         if (read_length >= 0) {
00721                             success = true;
00722 
00723                             if(read_size != NULL) {
00724                                 *read_size = *read_size + read_length;
00725                             }
00726                         }
00727                     } else {
00728                         // Retrieve the error class and code
00729                         if (_at->send("AT+UHTTPER=%d", httpProfile) &&
00730                             _at->recv("AT+UHTTPER=%*d,%d,%d",
00731                                       &(_httpProfiles[httpProfile].httpError.eClass),
00732                                       &(_httpProfiles[httpProfile].httpError.eCode)) &&
00733                             _at->recv("OK")) {
00734                             debug_if(_debug_trace_on, "HTTP error class %d, code %d\n",
00735                                     _httpProfiles[httpProfile].httpError.eClass,
00736                                     _httpProfiles[httpProfile].httpError.eCode);
00737                         }
00738                     }
00739                 } else if (!TIMEOUT(timer, _httpProfiles[httpProfile].timeout)) {
00740                     // Wait for URCs
00741                     _at->recv(UNNATURAL_STRING);
00742                 } else  {
00743                     _httpProfiles[httpProfile].pending = false;
00744                 }
00745             }
00746             timer.stop();
00747 
00748             at_set_timeout(at_timeout);
00749 
00750             if (!success) {
00751                 debug_if(_debug_trace_on, "%s: ERROR\n", getHttpCmd(httpCmd));
00752             }
00753 
00754         }
00755 
00756         UNLOCK();
00757     }
00758 
00759     return success ? NULL : &(_httpProfiles[httpProfile].httpError);
00760 }
00761 
00762 /**********************************************************************
00763  * PUBLIC METHODS: FTP
00764  **********************************************************************/
00765 
00766 // Set the blocking/timeout for FTP.
00767 bool UbloxATCellularInterfaceExt::ftpSetTimeout(int timeout)
00768 {
00769     LOCK();
00770     debug_if(_debug_trace_on, "ftpSetTimeout(%d)\n", timeout);
00771     _ftpTimeout = timeout;
00772     UNLOCK();
00773 
00774     return true;
00775 }
00776 
00777 // Reset the FTP configuration back to defaults.
00778 // Note: not all modrmd support all parameters,
00779 // hence the void return code.
00780 void UbloxATCellularInterfaceExt::ftpResetPar()
00781 {
00782     LOCK();
00783     debug_if(_debug_trace_on, "ftpResetPar()\n");
00784     for (int x = 0; x < NUM_FTP_OP_CODES; x++) {
00785         if (_at->send("AT+UFTP=%d", x)) {
00786             _at->recv("OK");
00787         }
00788     }
00789     UNLOCK();
00790 }
00791 
00792 // Set FTP parameters.
00793 bool UbloxATCellularInterfaceExt::ftpSetPar(FtpOpCode ftpOpCode,
00794                                             const char * ftpInPar)
00795 {
00796     bool success = false;
00797     int ftpInParNum = 0;
00798     LOCK();
00799 
00800     debug_if(_debug_trace_on, "ftpSetPar(%d, %s)\n", ftpOpCode, ftpInPar);
00801     switch (ftpOpCode) {
00802         case FTP_IP_ADDRESS:         // 0
00803         case FTP_SERVER_NAME:        // 1
00804         case FTP_USER_NAME:          // 2
00805         case FTP_PASSWORD:           // 3
00806         case FTP_ACCOUNT:            // 4
00807             success = _at->send("AT+UFTP=%d,\"%s\"", ftpOpCode, ftpInPar) &&
00808                       _at->recv("OK");
00809             break;
00810         case FTP_INACTIVITY_TIMEOUT: // 5
00811         case FTP_MODE:               // 6
00812         case FTP_SERVER_PORT:        // 7
00813         case FTP_SECURE:             // 8
00814             ftpInParNum = atoi(ftpInPar);
00815             success = _at->send("AT+UFTP=%d,%d", ftpOpCode, ftpInParNum) &&
00816                       _at->recv("OK");
00817             break;
00818         default:
00819             debug_if(_debug_trace_on, "ftpSetPar: unknown ftpOpCode %d\n", ftpOpCode);
00820             break;
00821     }
00822 
00823     UNLOCK();
00824     return success;
00825 }
00826 
00827 // Perform an FTP command.
00828 UbloxATCellularInterfaceExt::Error * UbloxATCellularInterfaceExt::ftpCommand(FtpCmd ftpCmd,
00829                                                                              const char* file1,
00830                                                                              const char* file2,
00831                                                                              char* buf, int len,
00832                                                                              int offset)
00833 {
00834     bool atSuccess = false;
00835     bool success = false;
00836     int at_timeout;
00837     LOCK();
00838     at_timeout = _at_timeout; // Has to be inside LOCK()s
00839 
00840     debug_if(_debug_trace_on, "%s\n", getFtpCmd(ftpCmd));
00841     switch (ftpCmd) {
00842         case FTP_LOGOUT:
00843         case FTP_LOGIN:
00844             atSuccess = _at->send("AT+UFTPC=%d", ftpCmd) && _at->recv("OK");
00845             break;
00846         case FTP_DELETE_FILE:
00847         case FTP_CD:
00848         case FTP_MKDIR:
00849         case FTP_RMDIR:
00850         case FTP_FOTA_FILE:
00851             atSuccess = _at->send("AT+UFTPC=%d,\"%s\"", ftpCmd, file1) &&
00852                         _at->recv("OK");
00853             break;
00854         case FTP_RENAME_FILE:
00855             atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\"",
00856                                   ftpCmd, file1, file2) &&
00857                         _at->recv("OK");
00858             break;
00859         case FTP_GET_FILE:
00860         case FTP_PUT_FILE:
00861             if (file2 == NULL) {
00862                 file2 = file1;
00863             }
00864             atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\",%d",
00865                                   ftpCmd, file1, file2, offset) &&
00866                         _at->recv("OK");
00867             
00868             // Not all modules support continuing a GET/PUT (e.g.
00869             // Sara-G350 00S-00 doesn't), so if we receive an error,
00870             // try again without it
00871             if (!atSuccess) {
00872                 atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\"",
00873                                       ftpCmd, file1, file2) &&
00874                             _at->recv("OK");
00875             }
00876             break;
00877         case FTP_FILE_INFO:
00878         case FTP_LS:
00879             _ftpBuf = buf;
00880             _ftpBufLen = len;
00881             // Add a terminator in case nothing comes back
00882             if (_ftpBufLen > 0) {
00883                 *_ftpBuf = 0;
00884             }
00885             if (file1 == NULL) {
00886                 atSuccess = _at->send("AT+UFTPC=%d", ftpCmd) &&
00887                             _at->recv("OK");
00888             } else {
00889                 atSuccess = _at->send("AT+UFTPC=%d,\"%s\"", ftpCmd, file1) &&
00890                             _at->recv("OK");
00891             }
00892             break;
00893         default:
00894             debug_if(_debug_trace_on, "FTP command not recognised/supported\n");
00895             break;
00896     }
00897 
00898     // Wait for the result to arrive back
00899     if (atSuccess) {
00900         Timer timer;
00901 
00902         at_set_timeout(1000);
00903         _lastFtpOpCodeData = FTP_OP_CODE_UNUSED;
00904         _lastFtpOpCodeResult = FTP_OP_CODE_UNUSED;
00905         _lastFtpResult = -1; // just for safety
00906         // Waiting for result to arrive
00907         timer.start();
00908         while ((_lastFtpOpCodeResult == FTP_OP_CODE_UNUSED) &&
00909                 !TIMEOUT(timer, _ftpTimeout)) {
00910             _at->recv(UNNATURAL_STRING);
00911         }
00912         timer.stop();
00913 
00914         if ((_lastFtpOpCodeResult == ftpCmd) && (_lastFtpResult == 1)) {
00915             // Got a result for our FTP op code and it is good
00916             success = true;
00917         } else {
00918             // Retrieve the error class and code
00919             if (_at->send("AT+UFTPER") &&
00920                 _at->recv("+UFTPER:%d,%d", &(_ftpError.eClass), &(_ftpError.eCode)) &&
00921                 _at->recv("OK")) {
00922                 debug_if(_debug_trace_on, "FTP Error class %d, code %d\n",
00923                          _ftpError.eClass, _ftpError.eCode);
00924             }
00925         }
00926 
00927         at_set_timeout(at_timeout);
00928 
00929         if (!success) {
00930             debug_if(_debug_trace_on, "%s: ERROR\n", getFtpCmd(ftpCmd));
00931         }
00932     }
00933 
00934     // Set these back to nothing to stop the URC splatting
00935     _ftpBuf = NULL;
00936     _ftpBufLen = 0;
00937 
00938     UNLOCK();
00939     return success ? NULL : &_ftpError;
00940 }
00941 
00942 /**********************************************************************
00943  * PUBLIC METHODS: Cell Locate
00944  **********************************************************************/
00945 
00946 // Configure CellLocate TCP Aiding server.
00947 bool UbloxATCellularInterfaceExt::cellLocSrvTcp(const char* token,
00948                                                 const char* server_1,
00949                                                 const char* server_2,
00950                                                 int days, int period,
00951                                                 int resolution)
00952 {
00953     bool success = false;
00954     LOCK();
00955 
00956     if ((_dev_info.dev == DEV_LISA_U2_03S) || (_dev_info.dev  == DEV_SARA_U2)){
00957         success = _at->send("AT+UGSRV=\"%s\",\"%s\",\"%s\",%d,%d,%d",
00958                             server_1, server_2, token, days, period, resolution) &&
00959                   _at->recv("OK");
00960     }
00961 
00962     UNLOCK();
00963     return success;
00964 }
00965 
00966 // Configure CellLocate UDP Aiding server.
00967 bool UbloxATCellularInterfaceExt::cellLocSrvUdp(const char* server_1,
00968                                                 int port, int latency,
00969                                                 int mode)
00970 {
00971 
00972     bool success = false;
00973     LOCK();
00974 
00975     if (_dev_info.dev != DEV_TOBY_L2) {
00976         success = _at->send("AT+UGAOP=\"%s\",%d,%d,%d", server_1, port, latency, mode) &&
00977                   _at->recv("OK");
00978     }
00979 
00980     UNLOCK();
00981     return success;
00982 }
00983 
00984 // Configure Cell Locate location sensor.
00985 bool UbloxATCellularInterfaceExt::cellLocConfig(int scanMode)
00986 {
00987     bool success;
00988     LOCK();
00989 
00990     success = _at->send("AT+ULOCCELL=%d", scanMode) &&
00991               _at->recv("OK");
00992 
00993     UNLOCK();
00994     return success;
00995 }
00996 
00997 // Request CellLocate.
00998 bool UbloxATCellularInterfaceExt::cellLocRequest(CellSensType sensor,
00999                                                  int timeout,
01000                                                  int accuracy,
01001                                                  CellRespType type,
01002                                                  int hypothesis)
01003 {
01004     bool success = false;
01005 
01006     if ((hypothesis <= CELL_MAX_HYP) &&
01007         !((hypothesis > 1) && (type != CELL_MULTIHYP))) {
01008 
01009         LOCK();
01010 
01011         _locRcvPos = 0;
01012         _locExpPos = 0;
01013 
01014         for (int i = 0; i < hypothesis; i++) {
01015             _loc[i].validData = false;
01016         }
01017 
01018         // Switch on the URC but don't error on it as some
01019         // modules (e.g. Sara-G350) don't support it
01020         if (_at->send("AT+ULOCIND=1")) {
01021             _at->recv("OK");
01022         }
01023         // Switch on Cell Locate
01024         success = _at->send("AT+ULOC=2,%d,%d,%d,%d,%d", sensor, type, timeout, accuracy, hypothesis) &&
01025                   _at->recv("OK");
01026         // Answers are picked up by reacting to +ULOC
01027 
01028         UNLOCK();
01029     }
01030 
01031     return success;
01032 }
01033 
01034 // Get a position record.
01035 bool UbloxATCellularInterfaceExt::cellLocGetData(CellLocData *data, int index)
01036 {
01037     bool success = false;
01038 
01039     if (_loc[index].validData) {
01040         LOCK();
01041         memcpy(data, &_loc[index], sizeof(*_loc));
01042         success = true;
01043         UNLOCK();
01044     }
01045 
01046     return success;
01047 }
01048 
01049 // Get number of position records received.
01050 int UbloxATCellularInterfaceExt::cellLocGetRes()
01051 {
01052     int at_timeout;
01053     LOCK();
01054 
01055     at_timeout = _at_timeout; // Has to be inside LOCK()s
01056     at_set_timeout(1000);
01057     // Wait for URCs
01058     _at->recv(UNNATURAL_STRING);
01059     at_set_timeout(at_timeout);
01060 
01061     UNLOCK();
01062     return _locRcvPos;
01063 }
01064 
01065 // Get number of positions records expected to be received.
01066 int UbloxATCellularInterfaceExt::cellLocGetExpRes()
01067 {
01068     int numRecords = 0;
01069     LOCK();
01070 
01071     _at->recv("OK");
01072 
01073     if (_locRcvPos > 0) {
01074         numRecords = _locExpPos;
01075     }
01076 
01077     UNLOCK();
01078     return numRecords;
01079 }
01080 
01081 // End of file
01082