Implementation of the CellularInterface for u-blox C027 and C030 (non-N2xx flavour) modems that uses the IP stack on-board the cellular modem, hence not requiring LWIP (and so less RAM) and allowing any AT command exchanges to be carried out at the same time as data transfers (since the modem remains in AT mode all the time). This library may be used from mbed 5.5 onwards. If you need to use SMS, USSD or access the modem file system at the same time as using the CellularInterface then use ublox-at-cellular-interface-ext instead.

Dependents:   example-ublox-cellular-interface example-ublox-cellular-interface_r410M example-ublox-mbed-client example-ublox-cellular-interface ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers <title>UbloxATCellularInterface.cpp Source File</title>

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