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