u-blox / ublox-at-cellular-interface-ext

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