Rod Landers / ublox-at-cellular-interface-ext

Dependencies:   ublox-at-cellular-interface

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                              UbloxATCellularInterface(tx, rx, baud, debugOn)
00444 {
00445     // Zero HTTP stuff
00446     memset(_httpProfiles, 0, sizeof(_httpProfiles));
00447     for (unsigned int profile = 0; profile < sizeof(_httpProfiles) / sizeof(_httpProfiles[0]);
00448          profile++) {
00449         _httpProfiles[profile].modemHandle = HTTP_PROF_UNUSED;
00450     }
00451 
00452     // Zero FTP stuff
00453     _ftpTimeout = TIMEOUT_BLOCKING;
00454     _lastFtpOpCodeResult = FTP_OP_CODE_UNUSED;
00455     _lastFtpResult = 0;
00456     _lastFtpOpCodeData = FTP_OP_CODE_UNUSED;
00457     _ftpBuf = NULL;
00458     _ftpBufLen = 0;
00459     _ftpError.eClass = 0;
00460     _ftpError.eCode = 0;
00461 
00462     // Zero Cell Locate stuff
00463     _locRcvPos = 0;
00464     _locExpPos = 0;
00465 
00466     // URC handler for HTTP
00467     _at->oob("+UUHTTPCR", callback(this, &UbloxATCellularInterfaceExt::UUHTTPCR_URC));
00468 
00469     // URC handlers for FTP
00470     _at->oob("+UUFTPCR", callback(this, &UbloxATCellularInterfaceExt::UUFTPCR_URC));
00471     _at->oob("+UUFTPCD", callback(this, &UbloxATCellularInterfaceExt::UUFTPCD_URC));
00472 
00473     // URC handlers for Cell Locate
00474     _at->oob("+UULOCIND:", callback(this, &UbloxATCellularInterfaceExt::UULOCIND_URC));
00475     _at->oob("+UULOC:", callback(this, &UbloxATCellularInterfaceExt::UULOC_URC));
00476 }
00477 
00478 // Destructor.
00479 UbloxATCellularInterfaceExt::~UbloxATCellularInterfaceExt()
00480 {
00481 }
00482 
00483 /**********************************************************************
00484  * PUBLIC METHODS: HTTP
00485  **********************************************************************/
00486 
00487 // Find a free profile.
00488 int UbloxATCellularInterfaceExt::httpAllocProfile()
00489 {
00490     int profile = HTTP_PROF_UNUSED;
00491     LOCK();
00492 
00493     // Find a free HTTP profile
00494     profile = findProfile();
00495     debug_if(_debug_trace_on, "httpFindProfile: profile is %d\n", profile);
00496 
00497     if (profile != HTTP_PROF_UNUSED) {
00498         _httpProfiles[profile].modemHandle = 1;
00499         _httpProfiles[profile].timeout     = TIMEOUT_BLOCKING;
00500         _httpProfiles[profile].pending     = false;
00501         _httpProfiles[profile].cmd         = -1;
00502         _httpProfiles[profile].result      = -1;
00503     }
00504 
00505     UNLOCK();
00506     return profile;
00507 }
00508 
00509 // Free a profile.
00510 bool UbloxATCellularInterfaceExt::httpFreeProfile(int profile)
00511 {
00512     bool success = false;
00513     LOCK();
00514 
00515     if (IS_PROFILE(profile)) {
00516         debug_if(_debug_trace_on, "httpFreeProfile(%d)\n", profile);
00517         _httpProfiles[profile].modemHandle = HTTP_PROF_UNUSED;
00518         _httpProfiles[profile].timeout     = TIMEOUT_BLOCKING;
00519         _httpProfiles[profile].pending     = false;
00520         _httpProfiles[profile].cmd         = -1;
00521         _httpProfiles[profile].result      = -1;
00522         success = _at->send("AT+UHTTP=%d", profile) && _at->recv("OK");
00523     }
00524 
00525     UNLOCK();
00526     return success;
00527 }
00528 
00529 // Set the blocking/timeout state of a profile.
00530 bool UbloxATCellularInterfaceExt::httpSetTimeout(int profile, int timeout)
00531 {
00532     bool success = false;
00533     LOCK();
00534 
00535     debug_if(_debug_trace_on, "httpSetTimeout(%d, %d)\n", profile, timeout);
00536 
00537     if (IS_PROFILE(profile)) {
00538         _httpProfiles[profile].timeout = timeout;
00539         success = true;
00540     }
00541 
00542     UNLOCK();
00543     return success;
00544 }
00545 
00546 // Set a profile back to defaults.
00547 bool UbloxATCellularInterfaceExt::httpResetProfile(int httpProfile)
00548 {
00549     bool success = false;
00550     LOCK();
00551 
00552     debug_if(_debug_trace_on, "httpResetProfile(%d)\n", httpProfile);
00553     success = _at->send("AT+UHTTP=%d", httpProfile) && _at->recv("OK");
00554 
00555     UNLOCK();
00556     return success;
00557 }
00558 
00559 // Set HTTP parameters.
00560 bool UbloxATCellularInterfaceExt::httpSetPar(int httpProfile,
00561                                              HttpOpCode httpOpCode,
00562                                              const char * httpInPar)
00563 {
00564     bool success = false;
00565     int httpInParNum = 0;
00566     SocketAddress address;
00567 
00568     debug_if(_debug_trace_on, "httpSetPar(%d, %d, \"%s\")\n", httpProfile, httpOpCode, httpInPar);
00569     if (IS_PROFILE(httpProfile)) {
00570         LOCK();
00571 
00572         switch(httpOpCode) {
00573             case HTTP_IP_ADDRESS:   // 0
00574                 if (gethostbyname(httpInPar, &address) == NSAPI_ERROR_OK) {
00575                     success = _at->send("AT+UHTTP=%d,%d,\"%s\"",
00576                                         httpProfile, httpOpCode, address.get_ip_address()) &&
00577                               _at->recv("OK");
00578                 }
00579                 break;
00580             case HTTP_SERVER_NAME:  // 1
00581             case HTTP_USER_NAME:    // 2
00582             case HTTP_PASSWORD:     // 3
00583                 success = _at->send("AT+UHTTP=%d,%d,\"%s\"", httpProfile, httpOpCode, httpInPar) &&
00584                           _at->recv("OK");
00585                 break;
00586 
00587             case HTTP_AUTH_TYPE:    // 4
00588             case HTTP_SERVER_PORT:  // 5
00589                 httpInParNum = atoi(httpInPar);
00590                 success = _at->send("AT+UHTTP=%d,%d,%d", httpProfile, httpOpCode, httpInParNum) &&
00591                           _at->recv("OK");
00592                 break;
00593 
00594             case HTTP_SECURE:       // 6
00595                 httpInParNum = atoi(httpInPar);
00596                 success = _at->send("AT+UHTTP=%d,%d,%d", httpProfile, httpOpCode, httpInParNum) &&
00597                           _at->recv("OK");
00598                 break;
00599 
00600             default:
00601                 debug_if(_debug_trace_on, "httpSetPar: unknown httpOpCode %d\n", httpOpCode);
00602                 break;
00603         }
00604 
00605         UNLOCK();
00606     }
00607 
00608     return success;
00609 }
00610 
00611 // Perform an HTTP command.
00612 UbloxATCellularInterfaceExt::Error * UbloxATCellularInterfaceExt::httpCommand(int httpProfile,
00613                                                                               HttpCmd httpCmd,
00614                                                                               const char *httpPath,
00615                                                                               const char *rspFile,
00616                                                                               const char *sendStr,
00617                                                                               int httpContentType,
00618                                                                               const char *httpCustomPar,
00619                                                                               char *buf, int len)
00620 {
00621     bool atSuccess = false;
00622     bool success = false;
00623     int at_timeout;
00624     char defaultFilename[] = "http_last_response_x";
00625 
00626     debug_if(_debug_trace_on, "%s\n", getHttpCmd(httpCmd));
00627 
00628     if (IS_PROFILE(httpProfile)) {
00629         LOCK();
00630         at_timeout = _at_timeout; // Has to be inside LOCK()s
00631 
00632         if (rspFile == NULL) {
00633             sprintf(defaultFilename + sizeof (defaultFilename) - 2, "%1d", httpProfile);
00634             rspFile = defaultFilename;
00635         }
00636 
00637         switch (httpCmd) {
00638             case HTTP_HEAD:
00639                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00640                                       httpPath, rspFile) &&
00641                             _at->recv("OK");
00642                 break;
00643             case HTTP_GET:
00644                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00645                                       httpPath, rspFile) &&
00646                             _at->recv("OK");
00647                 break;
00648             case HTTP_DELETE:
00649                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\"", httpProfile, httpCmd,
00650                                       httpPath, rspFile) &&
00651                             _at->recv("OK");
00652                 break;
00653             case HTTP_PUT:
00654                 // In this case the parameter sendStr is a filename
00655                 atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\"", httpProfile, httpCmd,
00656                                       httpPath, rspFile, sendStr) &&
00657                             _at->recv("OK");
00658                 break;
00659             case HTTP_POST_FILE:
00660                 // In this case the parameter sendStr is a filename
00661                 if (httpContentType != 6) {
00662                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d",
00663                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00664                                           httpContentType) &&
00665                                 _at->recv("OK");
00666                 } else {
00667                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%s",
00668                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00669                                           httpContentType,
00670                                           httpCustomPar) &&
00671                                 _at->recv("OK");
00672                 }
00673                 break;
00674             case HTTP_POST_DATA:
00675                 // In this case the parameter sendStr is a string containing data
00676                 if (httpContentType != 6) {
00677                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d",
00678                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00679                                           httpContentType) &&
00680                                 _at->recv("OK");
00681                 } else {
00682                     atSuccess = _at->send("AT+UHTTPC=%d,%d,\"%s\",\"%s\",\"%s\",%d,%s",
00683                                           httpProfile, httpCmd, httpPath, rspFile, sendStr,
00684                                           httpContentType,
00685                                           httpCustomPar) &&
00686                                 _at->recv("OK");
00687                 }
00688                 break;
00689             default:
00690                 debug_if(_debug_trace_on, "HTTP command not recognised\n");
00691                 break;
00692         }
00693 
00694         if (atSuccess) {
00695             Timer timer;
00696 
00697             at_set_timeout(1000);
00698             _httpProfiles[httpProfile].pending = true;
00699             _httpProfiles[httpProfile].result = -1;
00700 
00701             // Waiting for unsolicited result code
00702             timer.start();
00703             while (_httpProfiles[httpProfile].pending) {
00704                 if (_httpProfiles[httpProfile].result != -1) {
00705                     // Received unsolicited: starting its analysis
00706                     _httpProfiles[httpProfile].pending = false;
00707                     if (_httpProfiles[httpProfile].result == 1) {
00708                         // Leave a short delay to make sure the file has been written
00709                         wait_ms(100);
00710                         // HTTP command successfully executed
00711                         if (readFile(rspFile, buf, len) >= 0) {
00712                             success = true;
00713                         }
00714                     } else {
00715                         // Retrieve the error class and code
00716                         if (_at->send("AT+UHTTPER=%d", httpProfile) &&
00717                             _at->recv("AT+UHTTPER=%*d,%d,%d",
00718                                       &(_httpProfiles[httpProfile].httpError.eClass),
00719                                       &(_httpProfiles[httpProfile].httpError.eCode)) &&
00720                             _at->recv("OK")) {
00721                             debug_if(_debug_trace_on, "HTTP error class %d, code %d\n",
00722                                     _httpProfiles[httpProfile].httpError.eClass,
00723                                     _httpProfiles[httpProfile].httpError.eCode);
00724                         }
00725                     }
00726                 } else if (!TIMEOUT(timer, _httpProfiles[httpProfile].timeout)) {
00727                     // Wait for URCs
00728                     _at->recv(UNNATURAL_STRING);
00729                 } else  {
00730                     _httpProfiles[httpProfile].pending = false;
00731                 }
00732             }
00733             timer.stop();
00734 
00735             at_set_timeout(at_timeout);
00736 
00737             if (!success) {
00738                 debug_if(_debug_trace_on, "%s: ERROR\n", getHttpCmd(httpCmd));
00739             }
00740 
00741         }
00742 
00743         UNLOCK();
00744     }
00745 
00746     return success ? NULL : &(_httpProfiles[httpProfile].httpError);
00747 }
00748 
00749 /**********************************************************************
00750  * PUBLIC METHODS: FTP
00751  **********************************************************************/
00752 
00753 // Set the blocking/timeout for FTP.
00754 bool UbloxATCellularInterfaceExt::ftpSetTimeout(int timeout)
00755 {
00756     LOCK();
00757     debug_if(_debug_trace_on, "ftpSetTimeout(%d)\n", timeout);
00758     _ftpTimeout = timeout;
00759     UNLOCK();
00760 
00761     return true;
00762 }
00763 
00764 // Reset the FTP configuration back to defaults.
00765 // Note: not all modrmd support all parameters,
00766 // hence the void return code.
00767 void UbloxATCellularInterfaceExt::ftpResetPar()
00768 {
00769     LOCK();
00770     debug_if(_debug_trace_on, "ftpResetPar()\n");
00771     for (int x = 0; x < NUM_FTP_OP_CODES; x++) {
00772         if (_at->send("AT+UFTP=%d", x)) {
00773             _at->recv("OK");
00774         }
00775     }
00776     UNLOCK();
00777 }
00778 
00779 // Set FTP parameters.
00780 bool UbloxATCellularInterfaceExt::ftpSetPar(FtpOpCode ftpOpCode,
00781                                             const char * ftpInPar)
00782 {
00783     bool success = false;
00784     int ftpInParNum = 0;
00785     LOCK();
00786 
00787     debug_if(_debug_trace_on, "ftpSetPar(%d, %s)\n", ftpOpCode, ftpInPar);
00788     switch (ftpOpCode) {
00789         case FTP_IP_ADDRESS:         // 0
00790         case FTP_SERVER_NAME:        // 1
00791         case FTP_USER_NAME:          // 2
00792         case FTP_PASSWORD:           // 3
00793         case FTP_ACCOUNT:            // 4
00794             success = _at->send("AT+UFTP=%d,\"%s\"", ftpOpCode, ftpInPar) &&
00795                       _at->recv("OK");
00796             break;
00797         case FTP_INACTIVITY_TIMEOUT: // 5
00798         case FTP_MODE:               // 6
00799         case FTP_SERVER_PORT:        // 7
00800         case FTP_SECURE:             // 8
00801             ftpInParNum = atoi(ftpInPar);
00802             success = _at->send("AT+UFTP=%d,%d", ftpOpCode, ftpInParNum) &&
00803                       _at->recv("OK");
00804             break;
00805         default:
00806             debug_if(_debug_trace_on, "ftpSetPar: unknown ftpOpCode %d\n", ftpOpCode);
00807             break;
00808     }
00809 
00810     UNLOCK();
00811     return success;
00812 }
00813 
00814 // Perform an FTP command.
00815 UbloxATCellularInterfaceExt::Error * UbloxATCellularInterfaceExt::ftpCommand(FtpCmd ftpCmd,
00816                                                                              const char* file1,
00817                                                                              const char* file2,
00818                                                                              char* buf, int len,
00819                                                                              int offset)
00820 {
00821     bool atSuccess = false;
00822     bool success = false;
00823     int at_timeout;
00824     LOCK();
00825     at_timeout = _at_timeout; // Has to be inside LOCK()s
00826 
00827     debug_if(_debug_trace_on, "%s\n", getFtpCmd(ftpCmd));
00828     switch (ftpCmd) {
00829         case FTP_LOGOUT:
00830         case FTP_LOGIN:
00831             atSuccess = _at->send("AT+UFTPC=%d", ftpCmd) && _at->recv("OK");
00832             break;
00833         case FTP_DELETE_FILE:
00834         case FTP_CD:
00835         case FTP_MKDIR:
00836         case FTP_RMDIR:
00837         case FTP_FOTA_FILE:
00838             atSuccess = _at->send("AT+UFTPC=%d,\"%s\"", ftpCmd, file1) &&
00839                         _at->recv("OK");
00840             break;
00841         case FTP_RENAME_FILE:
00842             atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\"",
00843                                   ftpCmd, file1, file2) &&
00844                         _at->recv("OK");
00845             break;
00846         case FTP_GET_FILE:
00847         case FTP_PUT_FILE:
00848             if (file2 == NULL) {
00849                 file2 = file1;
00850             }
00851             atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\",%d",
00852                                   ftpCmd, file1, file2, offset) &&
00853                         _at->recv("OK");
00854             
00855             // Not all modules support continuing a GET/PUT (e.g.
00856             // Sara-G350 00S-00 doesn't), so if we receive an error,
00857             // try again without it
00858             if (!atSuccess) {
00859                 atSuccess = _at->send("AT+UFTPC=%d,\"%s\",\"%s\"",
00860                                       ftpCmd, file1, file2) &&
00861                             _at->recv("OK");
00862             }
00863             break;
00864         case FTP_FILE_INFO:
00865         case FTP_LS:
00866             _ftpBuf = buf;
00867             _ftpBufLen = len;
00868             // Add a terminator in case nothing comes back
00869             if (_ftpBufLen > 0) {
00870                 *_ftpBuf = 0;
00871             }
00872             if (file1 == NULL) {
00873                 atSuccess = _at->send("AT+UFTPC=%d", ftpCmd) &&
00874                             _at->recv("OK");
00875             } else {
00876                 atSuccess = _at->send("AT+UFTPC=%d,\"%s\"", ftpCmd, file1) &&
00877                             _at->recv("OK");
00878             }
00879             break;
00880         default:
00881             debug_if(_debug_trace_on, "FTP command not recognised/supported\n");
00882             break;
00883     }
00884 
00885     // Wait for the result to arrive back
00886     if (atSuccess) {
00887         Timer timer;
00888 
00889         at_set_timeout(1000);
00890         _lastFtpOpCodeData = FTP_OP_CODE_UNUSED;
00891         _lastFtpOpCodeResult = FTP_OP_CODE_UNUSED;
00892         _lastFtpResult = -1; // just for safety
00893         // Waiting for result to arrive
00894         timer.start();
00895         while ((_lastFtpOpCodeResult == FTP_OP_CODE_UNUSED) &&
00896                 !TIMEOUT(timer, _ftpTimeout)) {
00897             _at->recv(UNNATURAL_STRING);
00898         }
00899         timer.stop();
00900 
00901         if ((_lastFtpOpCodeResult == ftpCmd) && (_lastFtpResult == 1)) {
00902             // Got a result for our FTP op code and it is good
00903             success = true;
00904         } else {
00905             // Retrieve the error class and code
00906             if (_at->send("AT+UFTPER") &&
00907                 _at->recv("+UFTPER:%d,%d", &(_ftpError.eClass), &(_ftpError.eCode)) &&
00908                 _at->recv("OK")) {
00909                 debug_if(_debug_trace_on, "FTP Error class %d, code %d\n",
00910                          _ftpError.eClass, _ftpError.eCode);
00911             }
00912         }
00913 
00914         at_set_timeout(at_timeout);
00915 
00916         if (!success) {
00917             debug_if(_debug_trace_on, "%s: ERROR\n", getFtpCmd(ftpCmd));
00918         }
00919     }
00920 
00921     // Set these back to nothing to stop the URC splatting
00922     _ftpBuf = NULL;
00923     _ftpBufLen = 0;
00924 
00925     UNLOCK();
00926     return success ? NULL : &_ftpError;
00927 }
00928 
00929 /**********************************************************************
00930  * PUBLIC METHODS: Cell Locate
00931  **********************************************************************/
00932 
00933 // Configure CellLocate TCP Aiding server.
00934 bool UbloxATCellularInterfaceExt::cellLocSrvTcp(const char* token,
00935                                                 const char* server_1,
00936                                                 const char* server_2,
00937                                                 int days, int period,
00938                                                 int resolution)
00939 {
00940     bool success = false;
00941     LOCK();
00942 
00943     if ((_dev_info.dev == DEV_LISA_U2_03S) || (_dev_info.dev  == DEV_SARA_U2)){
00944         success = _at->send("AT+UGSRV=\"%s\",\"%s\",\"%s\",%d,%d,%d",
00945                             server_1, server_2, token, days, period, resolution) &&
00946                   _at->recv("OK");
00947     }
00948 
00949     UNLOCK();
00950     return success;
00951 }
00952 
00953 // Configure CellLocate UDP Aiding server.
00954 bool UbloxATCellularInterfaceExt::cellLocSrvUdp(const char* server_1,
00955                                                 int port, int latency,
00956                                                 int mode)
00957 {
00958 
00959     bool success = false;
00960     LOCK();
00961 
00962     if (_dev_info.dev != DEV_TOBY_L2) {
00963         success = _at->send("AT+UGAOP=\"%s\",%d,%d,%d", server_1, port, latency, mode) &&
00964                   _at->recv("OK");
00965     }
00966 
00967     UNLOCK();
00968     return success;
00969 }
00970 
00971 // Configure Cell Locate location sensor.
00972 bool UbloxATCellularInterfaceExt::cellLocConfig(int scanMode)
00973 {
00974     bool success;
00975     LOCK();
00976 
00977     success = _at->send("AT+ULOCCELL=%d", scanMode) &&
00978               _at->recv("OK");
00979 
00980     UNLOCK();
00981     return success;
00982 }
00983 
00984 // Request CellLocate.
00985 bool UbloxATCellularInterfaceExt::cellLocRequest(CellSensType sensor,
00986                                                  int timeout,
00987                                                  int accuracy,
00988                                                  CellRespType type,
00989                                                  int hypothesis)
00990 {
00991     bool success = false;
00992 
00993     if ((hypothesis <= CELL_MAX_HYP) &&
00994         !((hypothesis > 1) && (type != CELL_MULTIHYP))) {
00995 
00996         LOCK();
00997 
00998         _locRcvPos = 0;
00999         _locExpPos = 0;
01000 
01001         for (int i = 0; i < hypothesis; i++) {
01002             _loc[i].validData = false;
01003         }
01004 
01005         // Switch on the URC but don't error on it as some
01006         // modules (e.g. Sara-G350) don't support it
01007         if (_at->send("AT+ULOCIND=1")) {
01008             _at->recv("OK");
01009         }
01010         // Switch on Cell Locate
01011         success = _at->send("AT+ULOC=2,%d,%d,%d,%d,%d", sensor, type, timeout, accuracy, hypothesis) &&
01012                   _at->recv("OK");
01013         // Answers are picked up by reacting to +ULOC
01014 
01015         UNLOCK();
01016     }
01017 
01018     return success;
01019 }
01020 
01021 // Get a position record.
01022 bool UbloxATCellularInterfaceExt::cellLocGetData(CellLocData *data, int index)
01023 {
01024     bool success = false;
01025 
01026     if (_loc[index].validData) {
01027         LOCK();
01028         memcpy(data, &_loc[index], sizeof(*_loc));
01029         success = true;
01030         UNLOCK();
01031     }
01032 
01033     return success;
01034 }
01035 
01036 // Get number of position records received.
01037 int UbloxATCellularInterfaceExt::cellLocGetRes()
01038 {
01039     int at_timeout;
01040     LOCK();
01041 
01042     at_timeout = _at_timeout; // Has to be inside LOCK()s
01043     at_set_timeout(1000);
01044     // Wait for URCs
01045     _at->recv(UNNATURAL_STRING);
01046     at_set_timeout(at_timeout);
01047 
01048     UNLOCK();
01049     return _locRcvPos;
01050 }
01051 
01052 // Get number of positions records expected to be received.
01053 int UbloxATCellularInterfaceExt::cellLocGetExpRes()
01054 {
01055     int numRecords = 0;
01056     LOCK();
01057 
01058     _at->recv("OK");
01059 
01060     if (_locRcvPos > 0) {
01061         numRecords = _locExpPos;
01062     }
01063 
01064     UNLOCK();
01065     return numRecords;
01066 }
01067 
01068 // End of file
01069