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