This class adds HTTP, FTP and CellLocate client support for u-blox modules for the C027 and C030 boards (excepting the C030 N2xx flavour) from mbed 5.5 onwards. The HTTP, FTP and CellLocate operations are all hosted on the module, minimizing RAM consumption in the mbed MCU. It also sub-classes ublox-cellular-driver-gen to bring in SMS, USSD and modem file system support if you need to use these functions at the same time as the cellular interface.
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