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