changes for R412M test cases
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 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