fork
Embed:
(wiki syntax)
Show/hide line numbers
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 1.7.2