Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: ublox-at-cellular-interface
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
Generated on Tue Jul 12 2022 18:46:36 by
1.7.2