New cellular update

Dependencies:  

Fork of ublox-at-cellular-interface-ext by u-blox

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             default:
00602                 debug_if(_debug_trace_on, "httpSetPar: unknown httpOpCode %d\n", httpOpCode);
00603                 break;
00604         }
00605 
00606         UNLOCK();
00607     }
00608 
00609     return success;
00610 }
00611 
00612 // Perform an HTTP command.
00613 UbloxATCellularInterfaceExt::Error * UbloxATCellularInterfaceExt::httpCommand(int httpProfile,
00614                                                                               HttpCmd httpCmd,
00615                                                                               const char *httpPath,
00616                                                                               const char *rspFile,
00617                                                                               const char *sendStr,
00618                                                                               int httpContentType,
00619                                                                               const char *httpCustomPar,
00620                                                                               char *buf, int len, int *read_size)
00621 {
00622     bool atSuccess = false;
00623     bool success = false;
00624     int at_timeout;
00625     char defaultFilename[] = "http_last_response_x";
00626 
00627     debug_if(_debug_trace_on, "%s\n", getHttpCmd(httpCmd));
00628 
00629     if (IS_PROFILE(httpProfile)) {
00630         LOCK();
00631         at_timeout = _at_timeout; // Has to be inside LOCK()s
00632 
00633         if (rspFile == NULL) {
00634             sprintf(defaultFilename + sizeof (defaultFilename) - 2, "%1d", httpProfile);
00635             rspFile = defaultFilename;
00636         }
00637 
00638         switch (httpCmd) {
00639             case HTTP_HEAD:
00640                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00641                                       httpPath, rspFile) &&
00642                             _at->recv("OK");
00643                 break;
00644             case HTTP_GET:
00645                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00646                                       httpPath, rspFile) &&
00647                             _at->recv("OK");
00648                 break;
00649             case HTTP_DELETE:
00650                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00651                                       httpPath, rspFile) &&
00652                             _at->recv("OK");
00653                 break;
00654             case HTTP_PUT:
00655                 // In this case the parameter sendStr is a filename
00656                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\"", httpProfile, httpCmd,
00657                                       httpPath, rspFile, sendStr) &&
00658                             _at->recv("OK");
00659                 break;
00660             case HTTP_POST_FILE:
00661                 // In this case the parameter sendStr is a filename
00662                 if (httpContentType != 6) {
00663                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d",
00664                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00665                                           httpContentType) &&
00666                                 _at->recv("OK");
00667                 } else {
00668                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%s",
00669                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00670                                           httpContentType,
00671                                           httpCustomPar) &&
00672                                 _at->recv("OK");
00673                 }
00674                 break;
00675             case HTTP_POST_DATA:
00676                 // In this case the parameter sendStr is a string containing data
00677                 if (httpContentType != 6) {
00678                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d",
00679                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00680                                           httpContentType) &&
00681                                 _at->recv("OK");
00682                 } else {
00683                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%s",
00684                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00685                                           httpContentType,
00686                                           httpCustomPar) &&
00687                                 _at->recv("OK");
00688                 }
00689                 break;
00690             default:
00691                 debug_if(_debug_trace_on, "HTTP command not recognised\n");
00692                 break;
00693         }
00694 
00695         if (atSuccess) {
00696             Timer timer;
00697             int read_length = 0;
00698 
00699             at_set_timeout(1000);
00700             _httpProfiles[httpProfile].pending = true;
00701             _httpProfiles[httpProfile].result = -1;
00702 
00703             // Waiting for unsolicited result code
00704             timer.start();
00705             while (_httpProfiles[httpProfile].pending) {
00706                 if (_httpProfiles[httpProfile].result != -1) {
00707                     // Received unsolicited: starting its analysis
00708                     _httpProfiles[httpProfile].pending = false;
00709                     if (_httpProfiles[httpProfile].result == 1) {
00710                         // Leave a short delay to make sure the file has been written
00711                         wait_ms(100);
00712                         // HTTP command successfully executed
00713                         read_length = readFile(rspFile, buf, len);
00714 
00715                         if (read_length >= 0) {
00716                             success = true;
00717 
00718                             if(read_size != NULL) {
00719                                 *read_size = *read_size + read_length;
00720                             }
00721                         }
00722                     } else {
00723                         // Retrieve the error class and code
00724                         if (_at->send("AT+UHTTPER=%d", httpProfile) &&
00725                             _at->recv("AT+UHTTPER=%*d,%d,%d",
00726                                       &(_httpProfiles[httpProfile].httpError.eClass),
00727                                       &(_httpProfiles[httpProfile].httpError.eCode)) &&
00728                             _at->recv("OK")) {
00729                             debug_if(_debug_trace_on, "HTTP error class %d, code %d\n",
00730                                     _httpProfiles[httpProfile].httpError.eClass,
00731                                     _httpProfiles[httpProfile].httpError.eCode);
00732                         }
00733                     }
00734                 } else if (!TIMEOUT(timer, _httpProfiles[httpProfile].timeout)) {
00735                     // Wait for URCs
00736                     _at->recv(UNNATURAL_STRING);
00737                 } else  {
00738                     _httpProfiles[httpProfile].pending = false;
00739                 }
00740             }
00741             timer.stop();
00742 
00743             at_set_timeout(at_timeout);
00744 
00745             if (!success) {
00746                 debug_if(_debug_trace_on, "%s: ERROR\n", getHttpCmd(httpCmd));
00747             }
00748 
00749         }
00750 
00751         UNLOCK();
00752     }
00753 
00754     return success ? NULL : &(_httpProfiles[httpProfile].httpError);
00755 }
00756 
00757 /**********************************************************************
00758  * PUBLIC METHODS: FTP
00759  **********************************************************************/
00760 
00761 // Set the blocking/timeout for FTP.
00762 bool UbloxATCellularInterfaceExt::ftpSetTimeout(int timeout)
00763 {
00764     LOCK();
00765     debug_if(_debug_trace_on, "ftpSetTimeout(%d)\n", timeout);
00766     _ftpTimeout = timeout;
00767     UNLOCK();
00768 
00769     return true;
00770 }
00771 
00772 // Reset the FTP configuration back to defaults.
00773 // Note: not all modrmd support all parameters,
00774 // hence the void return code.
00775 void UbloxATCellularInterfaceExt::ftpResetPar()
00776 {
00777     LOCK();
00778     debug_if(_debug_trace_on, "ftpResetPar()\n");
00779     for (int x = 0; x < NUM_FTP_OP_CODES; x++) {
00780         if (_at->send("AT+UFTP=%d", x)) {
00781             _at->recv("OK");
00782         }
00783     }
00784     UNLOCK();
00785 }
00786 
00787 // Set FTP parameters.
00788 bool UbloxATCellularInterfaceExt::ftpSetPar(FtpOpCode ftpOpCode,
00789                                             const char * ftpInPar)
00790 {
00791     bool success = false;
00792     int ftpInParNum = 0;
00793     LOCK();
00794 
00795     debug_if(_debug_trace_on, "ftpSetPar(%d, %s)\n", ftpOpCode, ftpInPar);
00796     switch (ftpOpCode) {
00797         case FTP_IP_ADDRESS:         // 0
00798         case FTP_SERVER_NAME:        // 1
00799         case FTP_USER_NAME:          // 2
00800         case FTP_PASSWORD:           // 3
00801         case FTP_ACCOUNT:            // 4
00802             success = _at->send("AT+UFTP=%d,\"%s\"", ftpOpCode, ftpInPar) &&
00803                       _at->recv("OK");
00804             break;
00805         case FTP_INACTIVITY_TIMEOUT: // 5
00806         case FTP_MODE:               // 6
00807         case FTP_SERVER_PORT:        // 7
00808         case FTP_SECURE:             // 8
00809             ftpInParNum = atoi(ftpInPar);
00810             success = _at->send("AT+UFTP=%d,%d", ftpOpCode, ftpInParNum) &&
00811                       _at->recv("OK");
00812             break;
00813         default:
00814             debug_if(_debug_trace_on, "ftpSetPar: unknown ftpOpCode %d\n", ftpOpCode);
00815             break;
00816     }
00817 
00818     UNLOCK();
00819     return success;
00820 }
00821 
00822 // Perform an FTP command.
00823 UbloxATCellularInterfaceExt::Error * UbloxATCellularInterfaceExt::ftpCommand(FtpCmd ftpCmd,
00824                                                                              const char* file1,
00825                                                                              const char* file2,
00826                                                                              char* buf, int len,
00827                                                                              int offset)
00828 {
00829     bool atSuccess = false;
00830     bool success = false;
00831     int at_timeout;
00832     LOCK();
00833     at_timeout = _at_timeout; // Has to be inside LOCK()s
00834 
00835     debug_if(_debug_trace_on, "%s\n", getFtpCmd(ftpCmd));
00836     switch (ftpCmd) {
00837         case FTP_LOGOUT:
00838         case FTP_LOGIN:
00839             atSuccess = _at->send("AT+UFTPC=%d", ftpCmd) && _at->recv("OK");
00840             break;
00841         case FTP_DELETE_FILE:
00842         case FTP_CD:
00843         case FTP_MKDIR:
00844         case FTP_RMDIR:
00845         case FTP_FOTA_FILE:
00846             atSuccess = _at->send("AT+UFTPC=%d,\"%s\"", ftpCmd, file1) &&
00847                         _at->recv("OK");
00848             break;
00849         case FTP_RENAME_FILE:
00850             atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\"",
00851                                   ftpCmd, file1, file2) &&
00852                         _at->recv("OK");
00853             break;
00854         case FTP_GET_FILE:
00855         case FTP_PUT_FILE:
00856             if (file2 == NULL) {
00857                 file2 = file1;
00858             }
00859             atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\",%d",
00860                                   ftpCmd, file1, file2, offset) &&
00861                         _at->recv("OK");
00862             
00863             // Not all modules support continuing a GET/PUT (e.g.
00864             // Sara-G350 00S-00 doesn't), so if we receive an error,
00865             // try again without it
00866             if (!atSuccess) {
00867                 atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\"",
00868                                       ftpCmd, file1, file2) &&
00869                             _at->recv("OK");
00870             }
00871             break;
00872         case FTP_FILE_INFO:
00873         case FTP_LS:
00874             _ftpBuf = buf;
00875             _ftpBufLen = len;
00876             // Add a terminator in case nothing comes back
00877             if (_ftpBufLen > 0) {
00878                 *_ftpBuf = 0;
00879             }
00880             if (file1 == NULL) {
00881                 atSuccess = _at->send("AT+UFTPC=%d", ftpCmd) &&
00882                             _at->recv("OK");
00883             } else {
00884                 atSuccess = _at->send("AT+UFTPC=%d,\"%s\"", ftpCmd, file1) &&
00885                             _at->recv("OK");
00886             }
00887             break;
00888         default:
00889             debug_if(_debug_trace_on, "FTP command not recognised/supported\n");
00890             break;
00891     }
00892 
00893     // Wait for the result to arrive back
00894     if (atSuccess) {
00895         Timer timer;
00896 
00897         at_set_timeout(1000);
00898         _lastFtpOpCodeData = FTP_OP_CODE_UNUSED;
00899         _lastFtpOpCodeResult = FTP_OP_CODE_UNUSED;
00900         _lastFtpResult = -1; // just for safety
00901         // Waiting for result to arrive
00902         timer.start();
00903         while ((_lastFtpOpCodeResult == FTP_OP_CODE_UNUSED) &&
00904                 !TIMEOUT(timer, _ftpTimeout)) {
00905             _at->recv(UNNATURAL_STRING);
00906         }
00907         timer.stop();
00908 
00909         if ((_lastFtpOpCodeResult == ftpCmd) && (_lastFtpResult == 1)) {
00910             // Got a result for our FTP op code and it is good
00911             success = true;
00912         } else {
00913             // Retrieve the error class and code
00914             if (_at->send("AT+UFTPER") &&
00915                 _at->recv("+UFTPER:%d,%d", &(_ftpError.eClass), &(_ftpError.eCode)) &&
00916                 _at->recv("OK")) {
00917                 debug_if(_debug_trace_on, "FTP Error class %d, code %d\n",
00918                          _ftpError.eClass, _ftpError.eCode);
00919             }
00920         }
00921 
00922         at_set_timeout(at_timeout);
00923 
00924         if (!success) {
00925             debug_if(_debug_trace_on, "%s: ERROR\n", getFtpCmd(ftpCmd));
00926         }
00927     }
00928 
00929     // Set these back to nothing to stop the URC splatting
00930     _ftpBuf = NULL;
00931     _ftpBufLen = 0;
00932 
00933     UNLOCK();
00934     return success ? NULL : &_ftpError;
00935 }
00936 
00937 /**********************************************************************
00938  * PUBLIC METHODS: Cell Locate
00939  **********************************************************************/
00940 
00941 // Configure CellLocate TCP Aiding server.
00942 bool UbloxATCellularInterfaceExt::cellLocSrvTcp(const char* token,
00943                                                 const char* server_1,
00944                                                 const char* server_2,
00945                                                 int days, int period,
00946                                                 int resolution)
00947 {
00948     bool success = false;
00949     LOCK();
00950 
00951     if ((_dev_info.dev == DEV_LISA_U2_03S) || (_dev_info.dev  == DEV_SARA_U2)){
00952         success = _at->send("AT+UGSRV=\"%s\",\"%s\",\"%s\",%d,%d,%d",
00953                             server_1, server_2, token, days, period, resolution) &&
00954                   _at->recv("OK");
00955     }
00956 
00957     UNLOCK();
00958     return success;
00959 }
00960 
00961 // Configure CellLocate UDP Aiding server.
00962 bool UbloxATCellularInterfaceExt::cellLocSrvUdp(const char* server_1,
00963                                                 int port, int latency,
00964                                                 int mode)
00965 {
00966 
00967     bool success = false;
00968     LOCK();
00969 
00970     if (_dev_info.dev != DEV_TOBY_L2) {
00971         success = _at->send("AT+UGAOP=\"%s\",%d,%d,%d", server_1, port, latency, mode) &&
00972                   _at->recv("OK");
00973     }
00974 
00975     UNLOCK();
00976     return success;
00977 }
00978 
00979 // Configure Cell Locate location sensor.
00980 bool UbloxATCellularInterfaceExt::cellLocConfig(int scanMode)
00981 {
00982     bool success;
00983     LOCK();
00984 
00985     success = _at->send("AT+ULOCCELL=%d", scanMode) &&
00986               _at->recv("OK");
00987 
00988     UNLOCK();
00989     return success;
00990 }
00991 
00992 // Request CellLocate.
00993 bool UbloxATCellularInterfaceExt::cellLocRequest(CellSensType sensor,
00994                                                  int timeout,
00995                                                  int accuracy,
00996                                                  CellRespType type,
00997                                                  int hypothesis)
00998 {
00999     bool success = false;
01000 
01001     if ((hypothesis <= CELL_MAX_HYP) &&
01002         !((hypothesis > 1) && (type != CELL_MULTIHYP))) {
01003 
01004         LOCK();
01005 
01006         _locRcvPos = 0;
01007         _locExpPos = 0;
01008 
01009         for (int i = 0; i < hypothesis; i++) {
01010             _loc[i].validData = false;
01011         }
01012 
01013         // Switch on the URC but don't error on it as some
01014         // modules (e.g. Sara-G350) don't support it
01015         if (_at->send("AT+ULOCIND=1")) {
01016             _at->recv("OK");
01017         }
01018         // Switch on Cell Locate
01019         success = _at->send("AT+ULOC=2,%d,%d,%d,%d,%d", sensor, type, timeout, accuracy, hypothesis) &&
01020                   _at->recv("OK");
01021         // Answers are picked up by reacting to +ULOC
01022 
01023         UNLOCK();
01024     }
01025 
01026     return success;
01027 }
01028 
01029 // Get a position record.
01030 bool UbloxATCellularInterfaceExt::cellLocGetData(CellLocData *data, int index)
01031 {
01032     bool success = false;
01033 
01034     if (_loc[index].validData) {
01035         LOCK();
01036         memcpy(data, &_loc[index], sizeof(*_loc));
01037         success = true;
01038         UNLOCK();
01039     }
01040 
01041     return success;
01042 }
01043 
01044 // Get number of position records received.
01045 int UbloxATCellularInterfaceExt::cellLocGetRes()
01046 {
01047     int at_timeout;
01048     LOCK();
01049 
01050     at_timeout = _at_timeout; // Has to be inside LOCK()s
01051     at_set_timeout(1000);
01052     // Wait for URCs
01053     _at->recv(UNNATURAL_STRING);
01054     at_set_timeout(at_timeout);
01055 
01056     UNLOCK();
01057     return _locRcvPos;
01058 }
01059 
01060 // Get number of positions records expected to be received.
01061 int UbloxATCellularInterfaceExt::cellLocGetExpRes()
01062 {
01063     int numRecords = 0;
01064     LOCK();
01065 
01066     _at->recv("OK");
01067 
01068     if (_locRcvPos > 0) {
01069         numRecords = _locExpPos;
01070     }
01071 
01072     UNLOCK();
01073     return numRecords;
01074 }
01075 
01076 // End of file
01077