ublox-at-cellular-interface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UbloxATCellularInterface.cpp Source File

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