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