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