ublox-at-cellular-interface
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 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 Sat Jul 23 2022 05:31:40 by 1.7.2