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.
UbloxATCellularInterface.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 "UbloxATCellularInterface.h" 00017 #include "mbed_poll.h" 00018 #include "nsapi.h" 00019 #include "APN_db.h" 00020 #ifdef FEATURE_COMMON_PAL 00021 #include "mbed_trace.h" 00022 #define TRACE_GROUP "UACI" 00023 #else 00024 #define tr_debug(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00025 #define tr_info(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00026 #define tr_warn(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00027 #define tr_error(format, ...) debug_if(_debug_trace_on, format "\n", ## __VA_ARGS__) 00028 #endif 00029 00030 /********************************************************************** 00031 * PRIVATE METHODS 00032 **********************************************************************/ 00033 00034 // Event thread for asynchronous received data handling. 00035 void UbloxATCellularInterface::handle_event(){ 00036 pollfh fhs; 00037 int at_timeout; 00038 fhs.fh = _fh; 00039 fhs.events = POLLIN; 00040 00041 while (_run_event_thread) { 00042 int count; 00043 count = poll(&fhs, 1, 1000); 00044 if (count > 0 && (fhs.revents & POLLIN)) { 00045 LOCK(); 00046 at_timeout = _at_timeout; 00047 at_set_timeout(10); // Avoid blocking but also make sure we don't 00048 // time out if we get ahead of the serial port 00049 _at->debug_on(false); // Debug here screws with the test output 00050 // Let the URCs run 00051 _at->recv(UNNATURAL_STRING); 00052 _at->debug_on(_debug_trace_on); 00053 at_set_timeout(at_timeout); 00054 UNLOCK(); 00055 } 00056 } 00057 } 00058 00059 // Find or create a socket from the list. 00060 UbloxATCellularInterface::SockCtrl * UbloxATCellularInterface::find_socket(int modem_handle) 00061 { 00062 UbloxATCellularInterface::SockCtrl *socket = NULL; 00063 00064 for (unsigned int x = 0; (socket == NULL) && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) { 00065 if (_sockets[x].modem_handle == modem_handle) { 00066 socket = &(_sockets[x]); 00067 } 00068 } 00069 00070 return socket; 00071 } 00072 00073 // Clear out the storage for a socket 00074 void UbloxATCellularInterface::clear_socket(UbloxATCellularInterface::SockCtrl * socket) 00075 { 00076 if (socket != NULL) { 00077 socket->modem_handle = SOCKET_UNUSED; 00078 socket->pending = 0; 00079 socket->callback = NULL; 00080 socket->data = NULL; 00081 } 00082 } 00083 00084 // Check that a socket pointer is valid 00085 bool UbloxATCellularInterface::check_socket(SockCtrl * socket) 00086 { 00087 bool success = false; 00088 00089 if (socket != NULL) { 00090 for (unsigned int x = 0; !success && (x < sizeof(_sockets) / sizeof(_sockets[0])); x++) { 00091 if (socket == &(_sockets[x])) { 00092 success = true; 00093 } 00094 } 00095 } 00096 00097 return success; 00098 } 00099 00100 // Convert nsapi_security_t to the modem security numbers 00101 int UbloxATCellularInterface::nsapi_security_to_modem_security(nsapi_security_t nsapi_security) 00102 { 00103 int modem_security = 3; 00104 00105 switch (nsapi_security) 00106 { 00107 case NSAPI_SECURITY_NONE: 00108 modem_security = 0; 00109 break; 00110 case NSAPI_SECURITY_PAP: 00111 modem_security = 1; 00112 break; 00113 case NSAPI_SECURITY_CHAP: 00114 modem_security = 2; 00115 break; 00116 #ifndef TARGET_UBLOX_C030_R41XM 00117 case NSAPI_SECURITY_UNKNOWN: 00118 modem_security = 3; 00119 break; 00120 default: 00121 modem_security = 3; 00122 break; 00123 #else 00124 default: 00125 modem_security = 0; 00126 break; 00127 #endif 00128 } 00129 00130 return modem_security; 00131 } 00132 00133 // Callback for Socket Read URC. 00134 void UbloxATCellularInterface::UUSORD_URC() 00135 { 00136 int a; 00137 int b; 00138 char buf[32]; 00139 // Note: not calling _at->recv() from here as we're 00140 // already in an _at->recv() 00141 // +UUSORD: <socket>,<length> 00142 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00143 00144 if (sscanf(buf, ": %d,%d", &a, &b) == 2) { 00145 SockCtrl *socket; 00146 socket = find_socket(a); 00147 if (socket != NULL) { 00148 socket->pending = b; 00149 // No debug prints here as they can affect timing 00150 // and cause data loss in UARTSerial 00151 if (socket->callback != NULL) { 00152 socket->callback(socket->data); 00153 } 00154 } 00155 } 00156 } 00157 } 00158 00159 // Callback for Socket Read From URC. 00160 void UbloxATCellularInterface::UUSORF_URC() 00161 { 00162 int a; 00163 int b; 00164 char buf[32]; 00165 // Note: not calling _at->recv() from here as we're 00166 // already in an _at->recv() 00167 // +UUSORF: <socket>,<length> 00168 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00169 if (sscanf(buf, ": %d,%d", &a, &b) == 2) { 00170 SockCtrl *socket; 00171 socket = find_socket(a); 00172 if (socket != NULL) { 00173 socket->pending = b; 00174 // No debug prints here as they can affect timing 00175 // and cause data loss in UARTSerial 00176 if (socket->callback != NULL) { 00177 socket->callback(socket->data); 00178 } 00179 } 00180 } 00181 } 00182 } 00183 00184 // Callback for Socket Close URC. 00185 void UbloxATCellularInterface::UUSOCL_URC() 00186 { 00187 int a; 00188 char buf[32]; 00189 // Note: not calling _at->recv() from here as we're 00190 // already in an _at->recv() 00191 // +UUSOCL: <socket> 00192 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00193 if (sscanf(buf, ": %d", &a) == 1) { 00194 SockCtrl *socket; 00195 socket = find_socket(a); 00196 tr_debug("Socket 0x%08x: handle %d closed by remote host", 00197 (unsigned int) socket, a); 00198 clear_socket(socket); 00199 } 00200 } 00201 } 00202 00203 // Callback for UUPSDD. 00204 void UbloxATCellularInterface::UUPSDD_URC() 00205 { 00206 int a; 00207 char buf[32]; 00208 // Note: not calling _at->recv() from here as we're 00209 // already in an _at->recv() 00210 // +UUPSDD: <socket> 00211 if (read_at_to_char(buf, sizeof (buf), '\n') > 0) { 00212 if (sscanf(buf, ": %d", &a) == 1) { 00213 SockCtrl *socket; 00214 socket = find_socket(a); 00215 tr_debug("Socket 0x%08x: handle %d connection lost", 00216 (unsigned int) socket, a); 00217 clear_socket(socket); 00218 if (_connection_status_cb) { 00219 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST); 00220 } 00221 } 00222 } 00223 } 00224 00225 /********************************************************************** 00226 * PROTECTED METHODS: GENERAL 00227 **********************************************************************/ 00228 00229 // Get the next set of credentials, based on IMSI. 00230 void UbloxATCellularInterface::get_next_credentials(const char ** config) 00231 { 00232 if (*config) { 00233 _apn = _APN_GET(*config); 00234 _uname = _APN_GET(*config); 00235 _pwd = _APN_GET(*config); 00236 } 00237 00238 _apn = _apn ? _apn : ""; 00239 _uname = _uname ? _uname : ""; 00240 _pwd = _pwd ? _pwd : ""; 00241 } 00242 00243 // Active a connection profile on board the modem. 00244 // Note: the AT interface should be locked before this is called. 00245 bool UbloxATCellularInterface::activate_profile(const char* apn, 00246 const char* username, 00247 const char* password, 00248 nsapi_security_t auth) 00249 { 00250 bool activated = false; 00251 bool success = false; 00252 int active = 0; 00253 int at_timeout = _at_timeout; 00254 SocketAddress address; 00255 00256 // Set up the APN 00257 if (*apn) { 00258 success = _at->send("AT+UPSD=" PROFILE ",1,\"%s\"", apn) && _at->recv("OK"); 00259 } 00260 if (success && *username) { 00261 success = _at->send("AT+UPSD=" PROFILE ",2,\"%s\"", username) && _at->recv("OK"); 00262 } 00263 if (success && *password) { 00264 success = _at->send("AT+UPSD=" PROFILE ",3,\"%s\"", password) && _at->recv("OK"); 00265 } 00266 00267 if (success) { 00268 // Set up dynamic IP address assignment. 00269 success = _at->send("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"") && _at->recv("OK"); 00270 // Set up the authentication protocol 00271 // 0 = none 00272 // 1 = PAP (Password Authentication Protocol) 00273 // 2 = CHAP (Challenge Handshake Authentication Protocol) 00274 for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE); 00275 success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) { 00276 if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) { 00277 if (_at->send("AT+UPSD=" PROFILE ",6,%d", protocol) && _at->recv("OK")) { 00278 at_set_timeout(3*60*1000); 00279 _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00280 at_set_timeout(at_timeout); 00281 } 00282 } 00283 } 00284 00285 Timer timer; 00286 timer.start(); 00287 while (timer.read() < 180) { 00288 if (_at->send("AT+UPSND=" PROFILE ",8") && _at->recv("+UPSND: %*d,%*d,%d\n", &active) && 00289 _at->recv("OK")) { 00290 if (active == 1) { 00291 tr_debug("Profile activated successfully"); 00292 activated = true; 00293 break; 00294 } else { 00295 tr_error("Profile still inactive"); 00296 rtos::ThisThread::sleep_for(5000); //Wait for 5 seconds and then try again 00297 } 00298 } 00299 } 00300 timer.stop(); 00301 } 00302 00303 return activated; 00304 } 00305 00306 // Activate a profile by reusing an external PDP context. 00307 // Note: the AT interface should be locked before this is called. 00308 bool UbloxATCellularInterface::activate_profile_reuse_external(void) 00309 { 00310 bool success = false; 00311 int cid = -1; 00312 SocketAddress address; 00313 int t; 00314 int at_timeout = _at_timeout; 00315 00316 //+CGDCONT: <cid>,"IP","<apn name>","<ip adr>",0,0,0,0,0,0 00317 if (_at->send("AT+CGDCONT?")) { 00318 char ip[NSAPI_IP_SIZE]; 00319 if (_at->recv("+CGDCONT: %d,\"IP\",\"%*[^\"]\",\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%*d,%*d,%*d,%*d,%*d,%*d", 00320 &t, ip) && 00321 _at->recv("OK")) { 00322 // Check if the IP address is valid 00323 if (address.set_ip_address(ip)) { 00324 cid = t; 00325 } 00326 } 00327 } 00328 00329 // If a context has been found, use it 00330 if ((cid != -1) && (_at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK"))) { 00331 // Activate, waiting 30 seconds for the connection to be made 00332 at_set_timeout(30000); 00333 success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00334 at_set_timeout(at_timeout); 00335 } 00336 00337 return success; 00338 } 00339 00340 // Activate a profile by context ID. 00341 // Note: the AT interface should be locked before this is called. 00342 bool UbloxATCellularInterface::activate_profile_by_cid(int cid, 00343 const char* apn, 00344 const char* username, 00345 const char* password, 00346 nsapi_security_t auth) 00347 { 00348 bool success = false; 00349 int at_timeout = _at_timeout; 00350 00351 #ifndef TARGET_UBLOX_C030_R41XM 00352 if (_at->send("AT+CGDCONT=%d,\"IP\",\"%s\"", cid, apn) && _at->recv("OK") && 00353 _at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, nsapi_security_to_modem_security(auth), 00354 username, password) && _at->recv("OK") && 00355 _at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK")) { 00356 00357 // Wait 30 seconds for the connection to be made 00358 at_set_timeout(30000); 00359 // Activate the protocol 00360 success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK"); 00361 at_set_timeout(at_timeout); 00362 } 00363 #else 00364 int modem_security = nsapi_security_to_modem_security(auth); 00365 if (_at->send("AT+CGDCONT=%d,\"IP\",\"%s\"", cid, apn) && _at->recv("OK")) { 00366 if ( modem_security == NSAPI_SECURITY_CHAP) { 00367 if (_at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, modem_security, 00368 password, username) && _at->recv("OK")) { 00369 success = true; 00370 } 00371 } else if (modem_security == NSAPI_SECURITY_NONE) { 00372 if (_at->send("AT+UAUTHREQ=%d,%d", cid, modem_security) && _at->recv("OK")) { 00373 success = true; 00374 } 00375 } else { 00376 if (_at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, modem_security, 00377 username, password) && _at->recv("OK")) { 00378 success = true; 00379 } 00380 } 00381 } 00382 #endif 00383 00384 return success; 00385 } 00386 00387 #ifdef TARGET_UBLOX_C030_R41XM 00388 //define PDP context for R412M 00389 bool UbloxATCellularInterface::define_context() 00390 { 00391 bool success = false; 00392 const char * config = NULL; 00393 LOCK(); 00394 00395 // If the caller hasn't entered an APN, try to find it 00396 if (_apn == NULL) { 00397 config = apnconfig(_dev_info.imsi); 00398 } 00399 00400 // Attempt to connect 00401 do { 00402 // Set up APN and IP protocol for PDP context 00403 get_next_credentials(&config); 00404 _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE; 00405 if (activate_profile_by_cid(1, _apn, _uname, _pwd, _auth)) { 00406 success = true; 00407 } 00408 } while (!success && config && *config); 00409 00410 if (!success) { 00411 tr_error("Failed to connect, check your APN/username/password"); 00412 } 00413 00414 UNLOCK(); 00415 return success; 00416 } 00417 bool UbloxATCellularInterface::activate_context() 00418 { 00419 bool status = false; 00420 int at_timeout; 00421 LOCK(); 00422 00423 at_timeout = _at_timeout; // Has to be inside LOCK()s 00424 at_set_timeout(150000); 00425 if (_at->send("AT+CGACT=1,1") && _at->recv("OK")) { 00426 status = true; 00427 } 00428 00429 at_set_timeout(at_timeout); 00430 00431 UNLOCK(); 00432 return status; 00433 } 00434 00435 bool UbloxATCellularInterface::is_context_active() 00436 { 00437 bool status = false; 00438 int at_timeout; 00439 int active = 0; 00440 LOCK(); 00441 00442 at_timeout = _at_timeout; // Has to be inside LOCK()s 00443 at_set_timeout(150000); 00444 if (_at->send("AT+CGACT?") && _at->recv("+CGACT: %*d,%d\n", &active) && 00445 _at->recv("OK")) { 00446 if (active == 1) { 00447 status = true; 00448 } 00449 } 00450 at_set_timeout(at_timeout); 00451 00452 UNLOCK(); 00453 return status; 00454 } 00455 #endif 00456 00457 // Connect the on board IP stack of the modem. 00458 bool UbloxATCellularInterface::connect_modem_stack() 00459 { 00460 bool success = false; 00461 int active = 0; 00462 const char * config = NULL; 00463 LOCK(); 00464 00465 // Check the profile 00466 if (_at->send("AT+UPSND=" PROFILE ",8") && _at->recv("+UPSND: %*d,%*d,%d\n", &active) && 00467 _at->recv("OK")) { 00468 if (active == 0) { 00469 // If the caller hasn't entered an APN, try to find it 00470 if (_apn == NULL) { 00471 config = apnconfig(_dev_info.imsi); 00472 } 00473 00474 // Attempt to connect 00475 do { 00476 // Set up APN and IP protocol for PDP context 00477 get_next_credentials(&config); 00478 _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE; 00479 if ((_dev_info.dev != DEV_TOBY_L2) && (_dev_info.dev != DEV_MPCI_L2)) { 00480 success = activate_profile(_apn, _uname, _pwd, _auth); 00481 } else { 00482 success = activate_profile_reuse_external(); 00483 if (success) { 00484 tr_debug("Reusing external context"); 00485 } else { 00486 success = activate_profile_by_cid(1, _apn, _uname, _pwd, _auth); 00487 } 00488 } 00489 } while (!success && config && *config); 00490 } else { 00491 // If the profile is already active, we're good 00492 success = true; 00493 } 00494 } 00495 00496 if (!success) { 00497 tr_error("Failed to connect, check your APN/username/password"); 00498 } 00499 00500 UNLOCK(); 00501 return success; 00502 } 00503 00504 // Disconnect the on board IP stack of the modem. 00505 bool UbloxATCellularInterface::disconnect_modem_stack() 00506 { 00507 bool success = false; 00508 int active; 00509 Timer t1; 00510 LOCK(); 00511 00512 if (get_ip_address() != NULL) { 00513 if (_at->send("AT+UPSDA=" PROFILE ",4") && _at->recv("OK")) { 00514 success = true; 00515 if (_connection_status_cb) { 00516 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST); 00517 } 00518 } 00519 } 00520 t1.start(); 00521 while (!(t1.read() >= 180)) { 00522 if (_at->send("AT+UPSND=" PROFILE ",8") && _at->recv("+UPSND: %*d,%*d,%d\n", &active) && _at->recv("OK")) { 00523 00524 if (active == 0) { //If context is deactivated, exit while loop and return status 00525 tr_debug("Profile deactivated successfully"); 00526 break; 00527 } 00528 else { 00529 tr_error("Profile still active"); 00530 rtos::ThisThread::sleep_for(5000); //Wait for 5 seconds and then try again 00531 } 00532 } 00533 } 00534 t1.stop(); 00535 00536 UNLOCK(); 00537 return success; 00538 } 00539 00540 /********************************************************************** 00541 * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS 00542 **********************************************************************/ 00543 00544 // Gain access to us. 00545 NetworkStack *UbloxATCellularInterface::get_stack() 00546 { 00547 return this; 00548 } 00549 00550 // Create a socket. 00551 nsapi_error_t UbloxATCellularInterface::socket_open(nsapi_socket_t *handle, 00552 nsapi_protocol_t proto) 00553 { 00554 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00555 int modem_handle; 00556 SockCtrl *socket; 00557 LOCK(); 00558 00559 // Find a free socket 00560 socket = find_socket(); 00561 tr_debug("socket_open(%d)", proto); 00562 00563 if (socket != NULL) { 00564 bool success = false; 00565 if (proto == NSAPI_UDP) { 00566 success = _at->send("AT+USOCR=17"); 00567 } else if (proto == NSAPI_TCP) { 00568 success = _at->send("AT+USOCR=6"); 00569 } else { 00570 nsapi_error = NSAPI_ERROR_UNSUPPORTED; 00571 } 00572 00573 if (success) { 00574 nsapi_error = NSAPI_ERROR_NO_SOCKET; 00575 if (_at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) && 00576 _at->recv("OK")) { 00577 tr_debug("Socket 0x%8x: handle %d was created", (unsigned int) socket, modem_handle); 00578 clear_socket(socket); 00579 socket->modem_handle = modem_handle; 00580 *handle = (nsapi_socket_t) socket; 00581 nsapi_error = NSAPI_ERROR_OK; 00582 } 00583 } 00584 } else { 00585 nsapi_error = NSAPI_ERROR_NO_MEMORY; 00586 } 00587 00588 UNLOCK(); 00589 return nsapi_error; 00590 } 00591 00592 // Close a socket. 00593 nsapi_error_t UbloxATCellularInterface::socket_close(nsapi_socket_t handle) 00594 { 00595 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00596 SockCtrl *socket = (SockCtrl *) handle; 00597 LOCK(); 00598 00599 tr_debug("socket_close(0x%08x)", (unsigned int) handle); 00600 00601 MBED_ASSERT (check_socket(socket)); 00602 00603 if (_at->send("AT+USOCL=%d", socket->modem_handle) && 00604 _at->recv("OK")) { 00605 clear_socket(socket); 00606 nsapi_error = NSAPI_ERROR_OK; 00607 } 00608 00609 UNLOCK(); 00610 return nsapi_error; 00611 } 00612 00613 // Bind a local port to a socket. 00614 nsapi_error_t UbloxATCellularInterface::socket_bind(nsapi_socket_t handle, 00615 const SocketAddress &address) 00616 { 00617 nsapi_error_t nsapi_error = NSAPI_ERROR_NO_SOCKET; 00618 int proto; 00619 int modem_handle; 00620 SockCtrl savedSocket; 00621 SockCtrl *socket = (SockCtrl *) handle; 00622 LOCK(); 00623 00624 tr_debug("socket_bind(0x%08x, :%d)", (unsigned int) handle, address.get_port()); 00625 00626 MBED_ASSERT (check_socket(socket)); 00627 00628 // Query the socket type 00629 if (_at->send("AT+USOCTL=%d,0", socket->modem_handle) && 00630 _at->recv("+USOCTL: %*d,0,%d\n", &proto) && 00631 _at->recv("OK")) { 00632 savedSocket = *socket; 00633 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00634 // Now close the socket and re-open it with the binding given 00635 if (_at->send("AT+USOCL=%d", socket->modem_handle) && 00636 _at->recv("OK")) { 00637 clear_socket(socket); 00638 nsapi_error = NSAPI_ERROR_CONNECTION_LOST; 00639 if (_at->send("AT+USOCR=%d,%d", proto, address.get_port()) && 00640 _at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) && 00641 _at->recv("OK")) { 00642 *socket = savedSocket; 00643 nsapi_error = NSAPI_ERROR_OK; 00644 } 00645 } 00646 } 00647 00648 UNLOCK(); 00649 return nsapi_error; 00650 } 00651 00652 // Connect to a socket 00653 nsapi_error_t UbloxATCellularInterface::socket_connect(nsapi_socket_t handle, 00654 const SocketAddress &address) 00655 { 00656 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 00657 SockCtrl *socket = (SockCtrl *) handle; 00658 LOCK(); 00659 00660 tr_debug("socket_connect(0x%08x, %s(:%d))", (unsigned int) handle, 00661 address.get_ip_address(), address.get_port()); 00662 00663 MBED_ASSERT (check_socket(socket)); 00664 00665 if (_at->send("AT+USOCO=%d,\"%s\",%d", socket->modem_handle, 00666 address.get_ip_address(), address.get_port()) && 00667 _at->recv("OK")) { 00668 nsapi_error = NSAPI_ERROR_OK; 00669 } 00670 00671 UNLOCK(); 00672 return nsapi_error; 00673 } 00674 00675 // Send to a socket. 00676 nsapi_size_or_error_t UbloxATCellularInterface::socket_send(nsapi_socket_t handle, 00677 const void *data, 00678 nsapi_size_t size) 00679 { 00680 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00681 bool success = true; 00682 const char *buf = (const char *) data; 00683 nsapi_size_t blk = MAX_WRITE_SIZE; 00684 nsapi_size_t count = size; 00685 SockCtrl *socket = (SockCtrl *) handle; 00686 00687 tr_debug("socket_send(0x%08x, 0x%08x, %d)", (unsigned int) handle, (unsigned int) data, size); 00688 00689 MBED_ASSERT (check_socket(socket)); 00690 00691 if (socket->modem_handle == SOCKET_UNUSED) { 00692 tr_debug("socket_send: socket closed"); 00693 return NSAPI_ERROR_NO_SOCKET; 00694 } 00695 00696 while ((count > 0) && success) { 00697 if (count < blk) { 00698 blk = count; 00699 } 00700 LOCK(); 00701 00702 if (_at->send("AT+USOWR=%d,%d", socket->modem_handle, blk) && _at->recv("@")) { 00703 wait_ms(50); 00704 if ((_at->write(buf, blk) < (int) blk) || 00705 !_at->recv("OK")) { 00706 success = false; 00707 } 00708 } else { 00709 success = false; 00710 } 00711 00712 UNLOCK(); 00713 buf += blk; 00714 count -= blk; 00715 } 00716 00717 if (success) { 00718 nsapi_error_size = size - count; 00719 if (_debug_trace_on) { 00720 tr_debug("socket_send: %d \"%*.*s\"", size, size, size, (char *) data); 00721 } 00722 } 00723 00724 return nsapi_error_size; 00725 } 00726 00727 // Send to an IP address. 00728 nsapi_size_or_error_t UbloxATCellularInterface::socket_sendto(nsapi_socket_t handle, 00729 const SocketAddress &address, 00730 const void *data, 00731 nsapi_size_t size) 00732 { 00733 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00734 bool success = true; 00735 const char *buf = (const char *) data; 00736 nsapi_size_t blk = MAX_WRITE_SIZE; 00737 nsapi_size_t count = size; 00738 SockCtrl *socket = (SockCtrl *) handle; 00739 00740 tr_debug("socket_sendto(0x%8x, %s(:%d), 0x%08x, %d)", (unsigned int) handle, 00741 address.get_ip_address(), address.get_port(), (unsigned int) data, size); 00742 00743 MBED_ASSERT (check_socket(socket)); 00744 00745 if (size > MAX_WRITE_SIZE) { 00746 tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE); 00747 } 00748 00749 while ((count > 0) && success) { 00750 if (count < blk) { 00751 blk = count; 00752 } 00753 LOCK(); 00754 00755 if (_at->send("AT+USOST=%d,\"%s\",%d,%d", socket->modem_handle, 00756 address.get_ip_address(), address.get_port(), blk) && 00757 _at->recv("@")) { 00758 wait_ms(50); 00759 if ((_at->write(buf, blk) >= (int) blk) && 00760 _at->recv("OK")) { 00761 } else { 00762 success = false; 00763 } 00764 } else { 00765 success = false; 00766 } 00767 00768 UNLOCK(); 00769 buf += blk; 00770 count -= blk; 00771 } 00772 00773 if (success) { 00774 nsapi_error_size = size - count; 00775 if (_debug_trace_on) { 00776 tr_debug("socket_sendto: %d \"%*.*s\"", size, size, size, (char *) data); 00777 } 00778 } 00779 00780 return nsapi_error_size; 00781 } 00782 00783 // Receive from a socket, TCP style. 00784 nsapi_size_or_error_t UbloxATCellularInterface::socket_recv(nsapi_socket_t handle, 00785 void *data, 00786 nsapi_size_t size) 00787 { 00788 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00789 bool success = true; 00790 char *buf = (char *) data; 00791 nsapi_size_t read_blk; 00792 nsapi_size_t count = 0; 00793 unsigned int usord_sz; 00794 int read_sz; 00795 Timer timer; 00796 SockCtrl *socket = (SockCtrl *) handle; 00797 00798 00799 tr_debug("socket_recv(0x%08x, 0x%08x, %d)", 00800 (unsigned int) handle, (unsigned int) data, size); 00801 00802 MBED_ASSERT (check_socket(socket)); 00803 00804 if (socket->modem_handle == SOCKET_UNUSED) { 00805 tr_debug("socket_recv: socket closed"); 00806 return NSAPI_ERROR_NO_SOCKET; 00807 } 00808 00809 timer.start(); 00810 00811 while (success && (size > 0)) { 00812 int at_timeout; 00813 LOCK(); 00814 at_timeout = _at_timeout; 00815 at_set_timeout(1000); 00816 00817 read_blk = MAX_READ_SIZE; 00818 if (read_blk > size) { 00819 read_blk = size; 00820 } 00821 if (socket->pending > 0) { 00822 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending", 00823 (unsigned int) socket, socket->modem_handle, socket->pending); 00824 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to 00825 // be able to read packets of any size without 00826 // losing characters in UARTSerial 00827 if (_at->send("AT+USORD=%d,%d", socket->modem_handle, read_blk) && 00828 _at->recv("+USORD: %*d,%d,\"", &usord_sz)) { 00829 // Must use what +USORD returns here as it may be less or more than we asked for 00830 if (usord_sz > socket->pending) { 00831 socket->pending = 0; 00832 } else { 00833 socket->pending -= usord_sz; 00834 } 00835 // Note: insert no debug between _at->recv() and _at->read(), no time... 00836 if (usord_sz > size) { 00837 usord_sz = size; 00838 } 00839 read_sz = _at->read(buf, usord_sz); 00840 if (read_sz > 0) { 00841 tr_debug("...read %d byte(s) from modem handle %d...", read_sz, 00842 socket->modem_handle); 00843 if (_debug_trace_on) { 00844 tr_debug("Read returned %d, |%*.*s|", read_sz, read_sz, read_sz, buf); 00845 } 00846 count += read_sz; 00847 buf += read_sz; 00848 size -= read_sz; 00849 } else { 00850 // read() should not fail 00851 success = false; 00852 } 00853 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending", 00854 (unsigned int) socket, socket->modem_handle, socket->pending); 00855 // Wait for the "OK" before continuing 00856 _at->recv("OK"); 00857 } else { 00858 // Should never fail to do _at->send()/_at->recv() 00859 success = false; 00860 } 00861 _at->debug_on(_debug_trace_on); 00862 } else if (timer.read_ms() < SOCKET_TIMEOUT) { 00863 // Wait for URCs 00864 _at->recv(UNNATURAL_STRING); 00865 } else { 00866 if (count == 0) { 00867 // Timeout with nothing received 00868 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; 00869 success = false; 00870 } 00871 size = 0; // This simply to cause an exit 00872 } 00873 00874 at_set_timeout(at_timeout); 00875 UNLOCK(); 00876 } 00877 timer.stop(); 00878 00879 if (success) { 00880 nsapi_error_size = count; 00881 } 00882 00883 if (_debug_trace_on) { 00884 tr_debug("socket_recv: %d \"%*.*s\"", count, count, count, buf - count); 00885 } else { 00886 tr_debug("socket_recv: received %d byte(s)", count); 00887 } 00888 00889 return nsapi_error_size; 00890 } 00891 00892 // Receive a packet over a UDP socket. 00893 nsapi_size_or_error_t UbloxATCellularInterface::socket_recvfrom(nsapi_socket_t handle, 00894 SocketAddress *address, 00895 void *data, 00896 nsapi_size_t size) 00897 { 00898 nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; 00899 bool success = true; 00900 char *buf = (char *) data; 00901 nsapi_size_t read_blk; 00902 nsapi_size_t count = 0; 00903 char ipAddress[NSAPI_IP_SIZE]; 00904 int port; 00905 unsigned int usorf_sz; 00906 int read_sz; 00907 Timer timer; 00908 SockCtrl *socket = (SockCtrl *) handle; 00909 00910 tr_debug("socket_recvfrom(0x%08x, 0x%08x, %d)", 00911 (unsigned int) handle, (unsigned int) data, size); 00912 00913 MBED_ASSERT (check_socket(socket)); 00914 00915 timer.start(); 00916 00917 while (success && (size > 0)) { 00918 int at_timeout; 00919 LOCK(); 00920 at_timeout = _at_timeout; 00921 at_set_timeout(1000); 00922 00923 read_blk = MAX_READ_SIZE; 00924 if (read_blk > size) { 00925 read_blk = size; 00926 } 00927 if (socket->pending > 0) { 00928 tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending", 00929 (unsigned int) socket, socket->modem_handle, socket->pending); 00930 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator 00931 00932 // Note: the maximum length of UDP packet we can receive comes from 00933 // fitting all of the following into one buffer: 00934 // 00935 // +USORF: xx,"max.len.ip.address.ipv4.or.ipv6",yyyyy,wwww,"the_data"\r\n 00936 // 00937 // where xx is the handle, max.len.ip.address.ipv4.or.ipv6 is NSAPI_IP_SIZE, 00938 // yyyyy is the port number (max 65536), wwww is the length of the data and 00939 // the_data is binary data. I make that 29 + 48 + len(the_data), 00940 // so the overhead is 77 bytes. 00941 00942 _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to 00943 // be able to read packets of any size without 00944 // losing characters in UARTSerial 00945 if (_at->send("AT+USORF=%d,%d", socket->modem_handle, read_blk) && 00946 _at->recv("+USORF: %*d,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%d,%d,\"", 00947 ipAddress, &port, &usorf_sz)) { 00948 // Must use what +USORF returns here as it may be less or more than we asked for 00949 if (usorf_sz > socket->pending) { 00950 socket->pending = 0; 00951 } else { 00952 socket->pending -= usorf_sz; 00953 } 00954 // Note: insert no debug between _at->recv() and _at->read(), no time... 00955 if (usorf_sz > size) { 00956 usorf_sz = size; 00957 } 00958 read_sz = _at->read(buf, usorf_sz); 00959 if (read_sz > 0) { 00960 address->set_ip_address(ipAddress); 00961 address->set_port(port); 00962 tr_debug("...read %d byte(s) from modem handle %d...", read_sz, 00963 socket->modem_handle); 00964 if (_debug_trace_on) { 00965 tr_debug("Read returned %d, |%*.*s|", read_sz, read_sz, read_sz, buf); 00966 } 00967 count += read_sz; 00968 buf += read_sz; 00969 size -= read_sz; 00970 if ((usorf_sz < read_blk) || (usorf_sz == MAX_READ_SIZE)) { 00971 size = 0; // If we've received less than we asked for, or 00972 // the max size, then a whole UDP packet has arrived and 00973 // this means DONE. 00974 } 00975 } else { 00976 // read() should not fail 00977 success = false; 00978 } 00979 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending", 00980 (unsigned int) socket, socket->modem_handle, socket->pending); 00981 // Wait for the "OK" before continuing 00982 _at->recv("OK"); 00983 } else { 00984 // Should never fail to do _at->send()/_at->recv() 00985 success = false; 00986 } 00987 _at->debug_on(_debug_trace_on); 00988 } else if (timer.read_ms() < SOCKET_TIMEOUT) { 00989 // Wait for URCs 00990 _at->recv(UNNATURAL_STRING); 00991 } else { 00992 if (count == 0) { 00993 // Timeout with nothing received 00994 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; 00995 success = false; 00996 } 00997 size = 0; // This simply to cause an exit 00998 } 00999 01000 at_set_timeout(at_timeout); 01001 UNLOCK(); 01002 } 01003 timer.stop(); 01004 01005 if (success) { 01006 nsapi_error_size = count; 01007 } 01008 01009 if (_debug_trace_on) { 01010 tr_debug("socket_recvfrom: %d \"%*.*s\"", count, count, count, buf - count); 01011 } else { 01012 tr_debug("socket_recvfrom: received %d byte(s)", count); 01013 } 01014 01015 return nsapi_error_size; 01016 } 01017 01018 // Attach an event callback to a socket, required for asynchronous 01019 // data reception 01020 void UbloxATCellularInterface::socket_attach(nsapi_socket_t handle, 01021 void (*callback)(void *), 01022 void *data) 01023 { 01024 SockCtrl *socket = (SockCtrl *) handle; 01025 01026 MBED_ASSERT (check_socket(socket)); 01027 01028 socket->callback = callback; 01029 socket->data = data; 01030 } 01031 01032 // Unsupported TCP server functions. 01033 nsapi_error_t UbloxATCellularInterface::socket_listen(nsapi_socket_t handle, 01034 int backlog) 01035 { 01036 return NSAPI_ERROR_UNSUPPORTED; 01037 } 01038 nsapi_error_t UbloxATCellularInterface::socket_accept(nsapi_socket_t server, 01039 nsapi_socket_t *handle, 01040 SocketAddress *address) 01041 { 01042 return NSAPI_ERROR_UNSUPPORTED; 01043 } 01044 01045 // Unsupported option functions. 01046 nsapi_error_t UbloxATCellularInterface::setsockopt(nsapi_socket_t handle, 01047 int level, int optname, 01048 const void *optval, 01049 unsigned optlen) 01050 { 01051 return NSAPI_ERROR_UNSUPPORTED; 01052 } 01053 nsapi_error_t UbloxATCellularInterface::getsockopt(nsapi_socket_t handle, 01054 int level, int optname, 01055 void *optval, 01056 unsigned *optlen) 01057 { 01058 return NSAPI_ERROR_UNSUPPORTED; 01059 } 01060 01061 /********************************************************************** 01062 * PUBLIC METHODS 01063 **********************************************************************/ 01064 01065 // Constructor. 01066 UbloxATCellularInterface::UbloxATCellularInterface(PinName tx, 01067 PinName rx, 01068 int baud, 01069 bool debug_on, 01070 osPriority priority) 01071 { 01072 _sim_pin_check_change_pending = false; 01073 _sim_pin_check_change_pending_enabled_value = false; 01074 _sim_pin_change_pending = false; 01075 _sim_pin_change_pending_new_pin_value = NULL; 01076 _run_event_thread = true; 01077 _apn = NULL; 01078 _uname = NULL; 01079 _pwd = NULL; 01080 01081 01082 01083 01084 // Initialise sockets storage 01085 memset(_sockets, 0, sizeof(_sockets)); 01086 for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) { 01087 _sockets[socket].modem_handle = SOCKET_UNUSED; 01088 _sockets[socket].callback = NULL; 01089 _sockets[socket].data = NULL; 01090 } 01091 01092 // The authentication to use 01093 _auth = NSAPI_SECURITY_UNKNOWN; 01094 01095 // Nullify the temporary IP address storage 01096 _ip = NULL; 01097 _connection_status_cb = NULL; 01098 01099 01100 // Initialise the base class, which starts the AT parser 01101 baseClassInit(tx, rx, baud, debug_on); 01102 01103 // Start the event handler thread for Rx data 01104 event_thread.start(callback(this, &UbloxATCellularInterface::handle_event)); 01105 event_thread.set_priority(priority); 01106 01107 // URC handlers for sockets 01108 _at->oob("+UUSORD", callback(this, &UbloxATCellularInterface::UUSORD_URC)); 01109 _at->oob("+UUSORF", callback(this, &UbloxATCellularInterface::UUSORF_URC)); 01110 _at->oob("+UUSOCL", callback(this, &UbloxATCellularInterface::UUSOCL_URC)); 01111 _at->oob("+UUPSDD", callback(this, &UbloxATCellularInterface::UUPSDD_URC)); 01112 } 01113 01114 // Destructor. 01115 UbloxATCellularInterface::~UbloxATCellularInterface() 01116 { 01117 // Let the event thread shut down tidily 01118 _run_event_thread = false; 01119 event_thread.join(); 01120 01121 // Free _ip if it was ever allocated 01122 free(_ip); 01123 } 01124 01125 // Set the authentication scheme. 01126 void UbloxATCellularInterface::set_authentication(nsapi_security_t auth) 01127 { 01128 _auth = auth; 01129 } 01130 01131 // Set APN, user name and password. 01132 void UbloxATCellularInterface::set_credentials(const char *apn, 01133 const char *uname, 01134 const char *pwd) 01135 { 01136 _apn = apn; 01137 _uname = uname; 01138 _pwd = pwd; 01139 } 01140 01141 // Set PIN. 01142 void UbloxATCellularInterface::set_sim_pin(const char *pin) 01143 { 01144 set_pin(pin); 01145 } 01146 01147 // Get the IP address of a host. 01148 nsapi_error_t UbloxATCellularInterface::gethostbyname(const char *host, 01149 SocketAddress *address, 01150 nsapi_version_t version) 01151 { 01152 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01153 01154 01155 if (address->set_ip_address(host)) { 01156 nsapi_error = NSAPI_ERROR_OK; 01157 } else { 01158 int at_timeout; 01159 char ipAddress[NSAPI_IP_SIZE]; 01160 LOCK(); 01161 // This interrogation can sometimes take longer than the usual 8 seconds 01162 at_timeout = _at_timeout; 01163 at_set_timeout(60000); 01164 memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator 01165 if (_at->send("AT+UDNSRN=0,\"%s\"", host) && 01166 _at->recv("+UDNSRN: \"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", ipAddress) && 01167 _at->recv("OK")) { 01168 if (address->set_ip_address(ipAddress)) { 01169 nsapi_error = NSAPI_ERROR_OK; 01170 } 01171 } 01172 at_set_timeout(at_timeout); 01173 UNLOCK(); 01174 } 01175 01176 return nsapi_error; 01177 } 01178 01179 // Make a cellular connection 01180 nsapi_error_t UbloxATCellularInterface::connect(const char *sim_pin, 01181 const char *apn, 01182 const char *uname, 01183 const char *pwd) 01184 { 01185 nsapi_error_t nsapi_error; 01186 01187 if (sim_pin != NULL) { 01188 _pin = sim_pin; 01189 } 01190 01191 if (apn != NULL) { 01192 _apn = apn; 01193 } 01194 01195 if ((uname != NULL) && (pwd != NULL)) { 01196 _uname = uname; 01197 _pwd = pwd; 01198 } else { 01199 _uname = NULL; 01200 _pwd = NULL; 01201 } 01202 01203 nsapi_error = connect(); 01204 01205 return nsapi_error; 01206 } 01207 01208 // Make a cellular connection using the IP stack on board the cellular modem 01209 nsapi_error_t UbloxATCellularInterface::connect() 01210 { 01211 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01212 bool registered = false; 01213 01214 // Set up modem and then register with the network 01215 if (init()) { 01216 nsapi_error = NSAPI_ERROR_NO_CONNECTION; 01217 // Perform any pending SIM actions 01218 if (_sim_pin_check_change_pending) { 01219 if (!sim_pin_check_enable(_sim_pin_check_change_pending_enabled_value)) { 01220 nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01221 } 01222 _sim_pin_check_change_pending = false; 01223 } 01224 if (_sim_pin_change_pending) { 01225 if (!change_sim_pin(_sim_pin_change_pending_new_pin_value)) { 01226 nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01227 } 01228 _sim_pin_change_pending = false; 01229 } 01230 #ifdef TARGET_UBLOX_C030_R41XM 01231 define_context(); 01232 #endif 01233 if (nsapi_error == NSAPI_ERROR_NO_CONNECTION) { 01234 for (int retries = 0; !registered && (retries < 3); retries++) { 01235 if (nwk_registration()) { 01236 registered = true; 01237 #ifdef TARGET_UBLOX_C030_R41XM 01238 if (is_context_active()) { 01239 nsapi_error = NSAPI_ERROR_OK; 01240 tr_info("Context is already active\r\n"); 01241 } else { 01242 tr_info("Context is not active, activating it.\r\n"); 01243 if (activate_context()) { 01244 nsapi_error = NSAPI_ERROR_OK; 01245 } 01246 } 01247 #endif 01248 } 01249 } 01250 } 01251 } 01252 #ifndef TARGET_UBLOX_C030_R41XM 01253 // Attempt to establish a connection 01254 if (registered && connect_modem_stack()) { 01255 nsapi_error = NSAPI_ERROR_OK; 01256 } 01257 #endif 01258 return nsapi_error; 01259 } 01260 01261 // User initiated disconnect. 01262 nsapi_error_t UbloxATCellularInterface::disconnect() 01263 { 01264 nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01265 #ifdef TARGET_UBLOX_C030_R41XM 01266 if (nwk_deregistration()) { 01267 if (_connection_status_cb) { 01268 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST); 01269 } 01270 #else 01271 if (disconnect_modem_stack() && nwk_deregistration()) { 01272 #endif 01273 nsapi_error = NSAPI_ERROR_OK; 01274 } 01275 01276 return nsapi_error; 01277 } 01278 01279 // Enable or disable SIM PIN check lock. 01280 nsapi_error_t UbloxATCellularInterface::set_sim_pin_check(bool set, 01281 bool immediate, 01282 const char *sim_pin) 01283 { 01284 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01285 01286 if (sim_pin != NULL) { 01287 _pin = sim_pin; 01288 } 01289 01290 if (immediate) { 01291 if (init()) { 01292 if (sim_pin_check_enable(set)) { 01293 nsapi_error = NSAPI_ERROR_OK; 01294 } 01295 } else { 01296 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01297 } 01298 } else { 01299 nsapi_error = NSAPI_ERROR_OK; 01300 _sim_pin_check_change_pending = true; 01301 _sim_pin_check_change_pending_enabled_value = set; 01302 } 01303 01304 return nsapi_error; 01305 } 01306 01307 // Change the PIN code for the SIM card. 01308 nsapi_error_t UbloxATCellularInterface::set_new_sim_pin(const char *new_pin, 01309 bool immediate, 01310 const char *old_pin) 01311 { 01312 nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE; 01313 01314 if (old_pin != NULL) { 01315 _pin = old_pin; 01316 } 01317 01318 if (immediate) { 01319 if (init()) { 01320 if (change_sim_pin(new_pin)) { 01321 nsapi_error = NSAPI_ERROR_OK; 01322 } 01323 } else { 01324 nsapi_error = NSAPI_ERROR_DEVICE_ERROR; 01325 } 01326 } else { 01327 nsapi_error = NSAPI_ERROR_OK; 01328 _sim_pin_change_pending = true; 01329 _sim_pin_change_pending_new_pin_value = new_pin; 01330 } 01331 01332 return nsapi_error; 01333 } 01334 01335 // Determine if the connection is up. 01336 bool UbloxATCellularInterface::is_connected() 01337 { 01338 return get_ip_address() != NULL; 01339 } 01340 01341 // Get the IP address of the on-board modem IP stack. 01342 const char * UbloxATCellularInterface::get_ip_address() 01343 { 01344 SocketAddress address; 01345 LOCK(); 01346 01347 if (_ip == NULL) { 01348 // Temporary storage for an IP address string with terminator 01349 _ip = (char *) malloc(NSAPI_IP_SIZE); 01350 } 01351 01352 if (_ip != NULL) { 01353 memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator 01354 // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>] 01355 // If we get back a quoted "w.x.y.z" then we have an IP address, 01356 // otherwise we don't. 01357 #ifdef TARGET_UBLOX_C030_R41XM 01358 if (!_at->send("AT+CGPADDR=1") || 01359 !_at->recv("+CGPADDR: 1,%" u_stringify(NSAPI_IP_SIZE) "[^\n]\nOK\n", _ip) || 01360 !address.set_ip_address(_ip) || // Return NULL if the address is not a valid one 01361 !address) { // Return null if the address is zero 01362 free (_ip); 01363 _ip = NULL; 01364 } 01365 #else 01366 if (!_at->send("AT+UPSND=" PROFILE ",0") || 01367 !_at->recv("+UPSND: " PROFILE ",0,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", _ip) || 01368 !_at->recv("OK") || 01369 !address.set_ip_address(_ip) || // Return NULL if the address is not a valid one 01370 !address) { // Return null if the address is zero 01371 free (_ip); 01372 _ip = NULL; 01373 } 01374 #endif 01375 } 01376 01377 UNLOCK(); 01378 return _ip; 01379 } 01380 01381 // Get the local network mask. 01382 const char *UbloxATCellularInterface::get_netmask() 01383 { 01384 // Not implemented. 01385 return NULL; 01386 } 01387 01388 // Get the local gateways. 01389 const char *UbloxATCellularInterface::get_gateway() 01390 { 01391 return get_ip_address(); 01392 } 01393 01394 // Callback in case the connection is lost. 01395 void UbloxATCellularInterface::connection_status_cb(Callback<void(nsapi_error_t)> cb) 01396 { 01397 _connection_status_cb = cb; 01398 } 01399 01400 void UbloxATCellularInterface::set_plmn(const char *plmn) { 01401 01402 } 01403 01404 // End of file 01405
Generated on Sat Jul 16 2022 05:00:43 by
1.7.2