changes for R412M test cases

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 at_timeout = _at_timeout;
00253     SocketAddress address;
00254 
00255     // Set up the APN
00256     if (*apn) {
00257         success = _at->send("AT+UPSD=" PROFILE ",1,\"%s\"", apn) && _at->recv("OK");
00258     }
00259     if (success && *username) {
00260         success = _at->send("AT+UPSD=" PROFILE ",2,\"%s\"", username) && _at->recv("OK");
00261     }
00262     if (success && *password) {
00263         success = _at->send("AT+UPSD=" PROFILE ",3,\"%s\"", password) && _at->recv("OK");
00264     }
00265 
00266     if (success) {
00267         // Set up dynamic IP address assignment.
00268         success = _at->send("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"") && _at->recv("OK");
00269         // Set up the authentication protocol
00270         // 0 = none
00271         // 1 = PAP (Password Authentication Protocol)
00272         // 2 = CHAP (Challenge Handshake Authentication Protocol)
00273         for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
00274              success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
00275             if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
00276                 if (_at->send("AT+UPSD=" PROFILE ",6,%d", protocol) && _at->recv("OK")) {
00277                     // Activate, waiting 30 seconds for the connection to be made
00278                     at_set_timeout(30000);
00279                     activated = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK");
00280                     at_set_timeout(at_timeout);
00281                 }
00282             }
00283         }
00284     }
00285 
00286     return activated;
00287 }
00288 
00289 // Activate a profile by reusing an external PDP context.
00290 // Note: the AT interface should be locked before this is called.
00291 bool UbloxATCellularInterface::activate_profile_reuse_external(void)
00292 {
00293     bool success = false;
00294     int cid = -1;
00295     SocketAddress address;
00296     int t;
00297     int at_timeout = _at_timeout;
00298 
00299     //+CGDCONT: <cid>,"IP","<apn name>","<ip adr>",0,0,0,0,0,0
00300     if (_at->send("AT+CGDCONT?")) {
00301         char ip[NSAPI_IP_SIZE];
00302         if (_at->recv("+CGDCONT: %d,\"IP\",\"%*[^\"]\",\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%*d,%*d,%*d,%*d,%*d,%*d",
00303                       &t, ip) &&
00304             _at->recv("OK")) {
00305             // Check if the IP address is valid
00306             if (address.set_ip_address(ip)) {
00307                 cid = t;
00308             }
00309         }
00310     }
00311 
00312     // If a context has been found, use it
00313     if ((cid != -1) && (_at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK"))) {
00314         // Activate, waiting 30 seconds for the connection to be made
00315         at_set_timeout(30000);
00316         success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK");
00317         at_set_timeout(at_timeout);
00318     }
00319 
00320     return success;
00321 }
00322 
00323 // Activate a profile by context ID.
00324 // Note: the AT interface should be locked before this is called.
00325 bool UbloxATCellularInterface::activate_profile_by_cid(int cid,
00326                                                        const char* apn,
00327                                                        const char* username,
00328                                                        const char* password,
00329                                                        nsapi_security_t auth)
00330 {
00331     bool success = false;
00332     int at_timeout = _at_timeout;
00333 
00334 #ifndef TARGET_UBLOX_C030_R41XM
00335     if (_at->send("AT+CGDCONT=%d,\"IP\",\"%s\"", cid, apn) && _at->recv("OK") &&
00336         _at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, nsapi_security_to_modem_security(auth),
00337                   username, password) && _at->recv("OK") &&
00338         _at->send("AT+UPSD=" PROFILE ",100,%d", cid) && _at->recv("OK")) {
00339 
00340         // Wait 30 seconds for the connection to be made
00341         at_set_timeout(30000);
00342         // Activate the protocol
00343         success = _at->send("AT+UPSDA=" PROFILE ",3") && _at->recv("OK");
00344         at_set_timeout(at_timeout);
00345     }
00346 #else
00347     int modem_security = nsapi_security_to_modem_security(auth);
00348     if (_at->send("AT+CGDCONT=%d,\"IP\",\"%s\"", cid, apn) && _at->recv("OK")) {
00349         if ( modem_security == NSAPI_SECURITY_CHAP) {
00350             if (_at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, modem_security,
00351                         password, username) && _at->recv("OK")) {
00352                 success = true;
00353             }
00354         } else if (modem_security == NSAPI_SECURITY_NONE) {
00355             if (_at->send("AT+UAUTHREQ=%d,%d", cid, modem_security) && _at->recv("OK")) {
00356                 success = true;
00357             }
00358         } else {
00359             if (_at->send("AT+UAUTHREQ=%d,%d,\"%s\",\"%s\"", cid, modem_security,
00360                           username, password) && _at->recv("OK")) {
00361                 success = true;
00362             }
00363         }
00364     }
00365 #endif
00366 
00367     return success;
00368 }
00369 
00370 #ifdef TARGET_UBLOX_C030_R41XM
00371 //define PDP context for R412M
00372 bool UbloxATCellularInterface::define_context()
00373 {
00374     bool success = false;
00375     const char * config = NULL;
00376     LOCK();
00377 
00378     // If the caller hasn't entered an APN, try to find it
00379     if (_apn == NULL) {
00380         config = apnconfig(_dev_info.imsi);
00381     }
00382 
00383     // Attempt to connect
00384     do {
00385         // Set up APN and IP protocol for PDP context
00386         get_next_credentials(&config);
00387         _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE;
00388         if (activate_profile_by_cid(1, _apn, _uname, _pwd, _auth)) {
00389             success = true;
00390         }
00391     } while (!success && config && *config);
00392 
00393     if (!success) {
00394         tr_error("Failed to connect, check your APN/username/password");
00395     }
00396 
00397     UNLOCK();
00398     return success;
00399 }
00400 bool UbloxATCellularInterface::activate_context()
00401 {
00402     bool status = false;
00403     int at_timeout;
00404     LOCK();
00405 
00406     at_timeout = _at_timeout; // Has to be inside LOCK()s
00407     at_set_timeout(150000);
00408     if (_at->send("AT+CGACT=1,1") && _at->recv("OK")) {
00409         status = true;
00410     }
00411 
00412     at_set_timeout(at_timeout);
00413 
00414     UNLOCK();
00415     return status;
00416 }
00417 #endif
00418 
00419 // Connect the on board IP stack of the modem.
00420 bool UbloxATCellularInterface::connect_modem_stack()
00421 {
00422     bool success = false;
00423     int active = 0;
00424     const char * config = NULL;
00425     LOCK();
00426 
00427     // Check the profile
00428     if (_at->send("AT+UPSND=" PROFILE ",8") && _at->recv("+UPSND: %*d,%*d,%d\n", &active) &&
00429         _at->recv("OK")) {
00430         if (active == 0) {
00431             // If the caller hasn't entered an APN, try to find it
00432             if (_apn == NULL) {
00433                 config = apnconfig(_dev_info.imsi);
00434             }
00435 
00436             // Attempt to connect
00437             do {
00438                 // Set up APN and IP protocol for PDP context
00439                 get_next_credentials(&config);
00440                 _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE;
00441                 if ((_dev_info.dev != DEV_TOBY_L2) && (_dev_info.dev != DEV_MPCI_L2)) {
00442                     success = activate_profile(_apn, _uname, _pwd, _auth);
00443                 } else {
00444                     success = activate_profile_reuse_external();
00445                     if (success) {
00446                         tr_debug("Reusing external context");
00447                     } else {
00448                         success = activate_profile_by_cid(1, _apn, _uname, _pwd, _auth);
00449                     }
00450                 }
00451             } while (!success && config && *config);
00452         } else {
00453             // If the profile is already active, we're good
00454             success = true;
00455         }
00456     }
00457 
00458     if (!success) {
00459         tr_error("Failed to connect, check your APN/username/password");
00460     }
00461 
00462     UNLOCK();
00463     return success;
00464 }
00465 
00466 // Disconnect the on board IP stack of the modem.
00467 bool UbloxATCellularInterface::disconnect_modem_stack()
00468 {
00469     bool success = false;
00470     LOCK();
00471 
00472     if (get_ip_address() != NULL) {
00473         if (_at->send("AT+UPSDA=" PROFILE ",4") && _at->recv("OK")) {
00474             success = true;
00475             if (_connection_status_cb) {
00476                 _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST);
00477             }
00478         }
00479     }
00480 
00481     UNLOCK();
00482     return success;
00483 }
00484 
00485 /**********************************************************************
00486  * PROTECTED METHODS: NETWORK INTERFACE and SOCKETS
00487  **********************************************************************/
00488 
00489 // Gain access to us.
00490 NetworkStack *UbloxATCellularInterface::get_stack()
00491 {
00492     return this;
00493 }
00494 
00495 // Create a socket.
00496 nsapi_error_t UbloxATCellularInterface::socket_open(nsapi_socket_t *handle,
00497                                                     nsapi_protocol_t proto)
00498 {
00499     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00500     int modem_handle;
00501     SockCtrl *socket;
00502     LOCK();
00503 
00504     // Find a free socket
00505     socket = find_socket();
00506     tr_debug("socket_open(%d)", proto);
00507 
00508     if (socket != NULL) {
00509         bool success = false;
00510         if (proto == NSAPI_UDP) {
00511             success = _at->send("AT+USOCR=17");
00512         } else if (proto == NSAPI_TCP) {
00513             success = _at->send("AT+USOCR=6");
00514         } else  {
00515             nsapi_error = NSAPI_ERROR_UNSUPPORTED;
00516         }
00517 
00518         if (success) {
00519             nsapi_error = NSAPI_ERROR_NO_SOCKET;
00520             if (_at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) &&
00521                 _at->recv("OK")) {
00522                 tr_debug("Socket 0x%8x: handle %d was created", (unsigned int) socket, modem_handle);
00523                 clear_socket(socket);
00524                 socket->modem_handle         = modem_handle;
00525                 *handle = (nsapi_socket_t) socket;
00526                 nsapi_error = NSAPI_ERROR_OK;
00527             }
00528         }
00529     } else {
00530         nsapi_error = NSAPI_ERROR_NO_MEMORY;
00531     }
00532 
00533     UNLOCK();
00534     return nsapi_error;
00535 }
00536 
00537 // Close a socket.
00538 nsapi_error_t UbloxATCellularInterface::socket_close(nsapi_socket_t handle)
00539 {
00540     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00541     SockCtrl *socket = (SockCtrl *) handle;
00542     LOCK();
00543 
00544     tr_debug("socket_close(0x%08x)", (unsigned int) handle);
00545 
00546     MBED_ASSERT (check_socket(socket));
00547 
00548     if (_at->send("AT+USOCL=%d", socket->modem_handle) &&
00549         _at->recv("OK")) {
00550         clear_socket(socket);
00551         nsapi_error = NSAPI_ERROR_OK;
00552     }
00553 
00554     UNLOCK();
00555     return nsapi_error;
00556 }
00557 
00558 // Bind a local port to a socket.
00559 nsapi_error_t UbloxATCellularInterface::socket_bind(nsapi_socket_t handle,
00560                                                     const SocketAddress &address)
00561 {
00562     nsapi_error_t nsapi_error = NSAPI_ERROR_NO_SOCKET;
00563     int proto;
00564     int modem_handle;
00565     SockCtrl savedSocket;
00566     SockCtrl *socket = (SockCtrl *) handle;
00567     LOCK();
00568 
00569     tr_debug("socket_bind(0x%08x, :%d)", (unsigned int) handle, address.get_port());
00570 
00571     MBED_ASSERT (check_socket(socket));
00572 
00573     // Query the socket type
00574     if (_at->send("AT+USOCTL=%d,0", socket->modem_handle) &&
00575         _at->recv("+USOCTL: %*d,0,%d\n", &proto) &&
00576         _at->recv("OK")) {
00577         savedSocket = *socket;
00578         nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00579         // Now close the socket and re-open it with the binding given
00580         if (_at->send("AT+USOCL=%d", socket->modem_handle) &&
00581             _at->recv("OK")) {
00582             clear_socket(socket);
00583             nsapi_error = NSAPI_ERROR_CONNECTION_LOST;
00584             if (_at->send("AT+USOCR=%d,%d", proto, address.get_port()) &&
00585                 _at->recv("+USOCR: %d\n", &modem_handle) && (modem_handle != SOCKET_UNUSED) &&
00586                 _at->recv("OK")) {
00587                 *socket = savedSocket;
00588                 nsapi_error = NSAPI_ERROR_OK;
00589             }
00590         }
00591     }
00592 
00593     UNLOCK();
00594     return nsapi_error;
00595 }
00596 
00597 // Connect to a socket
00598 nsapi_error_t UbloxATCellularInterface::socket_connect(nsapi_socket_t handle,
00599                                                        const SocketAddress &address)
00600 {
00601     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
00602     SockCtrl *socket = (SockCtrl *) handle;
00603     LOCK();
00604 
00605     tr_debug("socket_connect(0x%08x, %s(:%d))", (unsigned int) handle,
00606              address.get_ip_address(), address.get_port());
00607 
00608     MBED_ASSERT (check_socket(socket));
00609 
00610     if (_at->send("AT+USOCO=%d,\"%s\",%d", socket->modem_handle,
00611                   address.get_ip_address(), address.get_port()) &&
00612         _at->recv("OK")) {
00613         nsapi_error = NSAPI_ERROR_OK;
00614     }
00615 
00616     UNLOCK();
00617     return nsapi_error;
00618 }
00619 
00620 // Send to a socket.
00621 nsapi_size_or_error_t UbloxATCellularInterface::socket_send(nsapi_socket_t handle,
00622                                                             const void *data,
00623                                                             nsapi_size_t size)
00624 {
00625     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
00626     bool success = true;
00627     const char *buf = (const char *) data;
00628     nsapi_size_t blk = MAX_WRITE_SIZE;
00629     nsapi_size_t count = size;
00630     SockCtrl *socket = (SockCtrl *) handle;
00631 
00632     tr_debug("socket_send(0x%08x, 0x%08x, %d)", (unsigned int) handle, (unsigned int) data, size);
00633 
00634     MBED_ASSERT (check_socket(socket));
00635 
00636     if (socket->modem_handle == SOCKET_UNUSED) {
00637         tr_debug("socket_send: socket closed");
00638         return NSAPI_ERROR_NO_SOCKET;
00639     }
00640 
00641     while ((count > 0) && success) {
00642         if (count < blk) {
00643             blk = count;
00644         }
00645         LOCK();
00646 
00647         if (_at->send("AT+USOWR=%d,%d", socket->modem_handle, blk) && _at->recv("@")) {
00648             wait_ms(50);
00649             if ((_at->write(buf, blk) < (int) blk) ||
00650                  !_at->recv("OK")) {
00651                 success = false;
00652             }
00653         } else {
00654             success = false;
00655         }
00656 
00657         UNLOCK();
00658         buf += blk;
00659         count -= blk;
00660     }
00661 
00662     if (success) {
00663         nsapi_error_size = size - count;
00664         if (_debug_trace_on) {
00665             tr_debug("socket_send: %d \"%*.*s\"", size, size, size, (char *) data);
00666         }
00667     }
00668 
00669     return nsapi_error_size;
00670 }
00671 
00672 // Send to an IP address.
00673 nsapi_size_or_error_t UbloxATCellularInterface::socket_sendto(nsapi_socket_t handle,
00674                                                               const SocketAddress &address,
00675                                                               const void *data,
00676                                                               nsapi_size_t size)
00677 {
00678     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
00679     bool success = true;
00680     const char *buf = (const char *) data;
00681     nsapi_size_t blk = MAX_WRITE_SIZE;
00682     nsapi_size_t count = size;
00683     SockCtrl *socket = (SockCtrl *) handle;
00684 
00685     tr_debug("socket_sendto(0x%8x, %s(:%d), 0x%08x, %d)", (unsigned int) handle,
00686              address.get_ip_address(), address.get_port(), (unsigned int) data, size);
00687 
00688     MBED_ASSERT (check_socket(socket));
00689 
00690     if (size > MAX_WRITE_SIZE) {
00691         tr_warn("WARNING: packet length %d is too big for one UDP packet (max %d), will be fragmented.", size, MAX_WRITE_SIZE);
00692     }
00693 
00694     while ((count > 0) && success) {
00695         if (count < blk) {
00696             blk = count;
00697         }
00698         LOCK();
00699 
00700         if (_at->send("AT+USOST=%d,\"%s\",%d,%d", socket->modem_handle,
00701                       address.get_ip_address(), address.get_port(), blk) &&
00702             _at->recv("@")) {
00703             wait_ms(50);
00704             if ((_at->write(buf, blk) >= (int) blk) &&
00705                  _at->recv("OK")) {
00706             } else {
00707                 success = false;
00708             }
00709         } else {
00710             success = false;
00711         }
00712 
00713         UNLOCK();
00714         buf += blk;
00715         count -= blk;
00716     }
00717 
00718     if (success) {
00719         nsapi_error_size = size - count;
00720         if (_debug_trace_on) {
00721             tr_debug("socket_sendto: %d \"%*.*s\"", size, size, size, (char *) data);
00722         }
00723     }
00724 
00725     return nsapi_error_size;
00726 }
00727 
00728 // Receive from a socket, TCP style.
00729 nsapi_size_or_error_t UbloxATCellularInterface::socket_recv(nsapi_socket_t handle,
00730                                                             void *data,
00731                                                             nsapi_size_t size)
00732 {
00733     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
00734     bool success = true;
00735     char *buf = (char *) data;
00736     nsapi_size_t read_blk;
00737     nsapi_size_t count = 0;
00738     unsigned int usord_sz;
00739     int read_sz;
00740     Timer timer;
00741     SockCtrl *socket = (SockCtrl *) handle;
00742 
00743 
00744     tr_debug("socket_recv(0x%08x, 0x%08x, %d)",
00745              (unsigned int) handle, (unsigned int) data, size);
00746 
00747     MBED_ASSERT (check_socket(socket));
00748 
00749     if (socket->modem_handle == SOCKET_UNUSED) {
00750         tr_debug("socket_recv: socket closed");
00751         return NSAPI_ERROR_NO_SOCKET;
00752     }
00753 
00754     timer.start();
00755 
00756     while (success && (size > 0)) {
00757         int at_timeout;
00758         LOCK();
00759         at_timeout = _at_timeout;
00760         at_set_timeout(1000);
00761 
00762         read_blk = MAX_READ_SIZE;
00763         if (read_blk > size) {
00764             read_blk = size;
00765         }
00766         if (socket->pending > 0) {
00767             tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending",
00768                      (unsigned int) socket, socket->modem_handle, socket->pending);
00769             _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to
00770                                   // be able to read packets of any size without
00771                                   // losing characters in UARTSerial
00772             if (_at->send("AT+USORD=%d,%d", socket->modem_handle, read_blk) &&
00773                 _at->recv("+USORD: %*d,%d,\"", &usord_sz)) {
00774                 // Must use what +USORD returns here as it may be less or more than we asked for
00775                 if (usord_sz > socket->pending) {
00776                     socket->pending = 0;
00777                 } else {
00778                     socket->pending -= usord_sz; 
00779                 }
00780                 // Note: insert no debug between _at->recv() and _at->read(), no time...
00781                 if (usord_sz > size) {
00782                     usord_sz = size;
00783                 }
00784                 read_sz = _at->read(buf, usord_sz);
00785                 if (read_sz > 0) {
00786                     tr_debug("...read %d byte(s) from modem handle %d...", read_sz,
00787                              socket->modem_handle);
00788                     if (_debug_trace_on) {
00789                         tr_debug("Read returned %d,  |%*.*s|", read_sz, read_sz, read_sz, buf);
00790                     }
00791                     count += read_sz;
00792                     buf += read_sz;
00793                     size -= read_sz;
00794                 } else {
00795                     // read() should not fail
00796                     success = false;
00797                 }
00798                 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending",
00799                          (unsigned int) socket, socket->modem_handle, socket->pending);
00800                 // Wait for the "OK" before continuing
00801                 _at->recv("OK");
00802             } else {
00803                 // Should never fail to do _at->send()/_at->recv()
00804                 success = false;
00805             }
00806             _at->debug_on(_debug_trace_on);
00807         } else if (timer.read_ms() < SOCKET_TIMEOUT) {
00808             // Wait for URCs
00809             _at->recv(UNNATURAL_STRING);
00810         } else {
00811             if (count == 0) {
00812                 // Timeout with nothing received
00813                 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK;
00814                 success = false;
00815             }
00816             size = 0; // This simply to cause an exit
00817         }
00818 
00819         at_set_timeout(at_timeout);
00820         UNLOCK();
00821     }
00822     timer.stop();
00823 
00824     if (success) {
00825         nsapi_error_size = count;
00826     }
00827 
00828     if (_debug_trace_on) {
00829         tr_debug("socket_recv: %d \"%*.*s\"", count, count, count, buf - count);
00830     } else {
00831         tr_debug("socket_recv: received %d byte(s)", count);
00832     }
00833 
00834     return nsapi_error_size;
00835 }
00836 
00837 // Receive a packet over a UDP socket.
00838 nsapi_size_or_error_t UbloxATCellularInterface::socket_recvfrom(nsapi_socket_t handle,
00839                                                                 SocketAddress *address,
00840                                                                 void *data,
00841                                                                 nsapi_size_t size)
00842 {
00843     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR;
00844     bool success = true;
00845     char *buf = (char *) data;
00846     nsapi_size_t read_blk;
00847     nsapi_size_t count = 0;
00848     char ipAddress[NSAPI_IP_SIZE];
00849     int port;
00850     unsigned int usorf_sz;
00851     int read_sz;
00852     Timer timer;
00853     SockCtrl *socket = (SockCtrl *) handle;
00854 
00855     tr_debug("socket_recvfrom(0x%08x, 0x%08x, %d)",
00856              (unsigned int) handle, (unsigned int) data, size);
00857 
00858     MBED_ASSERT (check_socket(socket));
00859 
00860     timer.start();
00861 
00862     while (success && (size > 0)) {
00863         int at_timeout;
00864         LOCK();
00865         at_timeout = _at_timeout;
00866         at_set_timeout(1000);
00867 
00868         read_blk = MAX_READ_SIZE;
00869         if (read_blk > size) {
00870             read_blk = size;
00871         }
00872         if (socket->pending > 0) {
00873             tr_debug("Socket 0x%08x: modem handle %d has %d byte(s) pending",
00874                      (unsigned int) socket, socket->modem_handle, socket->pending);
00875             memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator
00876 
00877             // Note: the maximum length of UDP packet we can receive comes from
00878             // fitting all of the following into one buffer:
00879             //
00880             // +USORF: xx,"max.len.ip.address.ipv4.or.ipv6",yyyyy,wwww,"the_data"\r\n
00881             //
00882             // where xx is the handle, max.len.ip.address.ipv4.or.ipv6 is NSAPI_IP_SIZE,
00883             // yyyyy is the port number (max 65536), wwww is the length of the data and
00884             // the_data is binary data. I make that 29 + 48 + len(the_data),
00885             // so the overhead is 77 bytes.
00886 
00887             _at->debug_on(false); // ABSOLUTELY no time for debug here if you want to
00888                                   // be able to read packets of any size without
00889                                   // losing characters in UARTSerial
00890             if (_at->send("AT+USORF=%d,%d", socket->modem_handle, read_blk) &&
00891                 _at->recv("+USORF: %*d,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\",%d,%d,\"",
00892                           ipAddress, &port, &usorf_sz)) {
00893                 // Must use what +USORF returns here as it may be less or more than we asked for
00894                 if (usorf_sz > socket->pending) {
00895                     socket->pending = 0;
00896                 } else {
00897                     socket->pending -= usorf_sz; 
00898                 }
00899                 // Note: insert no debug between _at->recv() and _at->read(), no time...
00900                 if (usorf_sz > size) {
00901                     usorf_sz = size;
00902                 }
00903                 read_sz = _at->read(buf, usorf_sz);
00904                 if (read_sz > 0) {
00905                     address->set_ip_address(ipAddress);
00906                     address->set_port(port);
00907                     tr_debug("...read %d byte(s) from modem handle %d...", read_sz,
00908                              socket->modem_handle);
00909                     if (_debug_trace_on) {
00910                         tr_debug("Read returned %d,  |%*.*s|", read_sz, read_sz, read_sz, buf);
00911                     }
00912                     count += read_sz;
00913                     buf += read_sz;
00914                     size -= read_sz;
00915                     if ((usorf_sz < read_blk) || (usorf_sz == MAX_READ_SIZE)) {
00916                         size = 0; // If we've received less than we asked for, or
00917                                   // the max size, then a whole UDP packet has arrived and
00918                                   // this means DONE.
00919                     }
00920                 } else {
00921                     // read() should not fail
00922                     success = false;
00923                 }
00924                 tr_debug("Socket 0x%08x: modem handle %d now has only %d byte(s) pending",
00925                          (unsigned int) socket, socket->modem_handle, socket->pending);
00926                 // Wait for the "OK" before continuing
00927                 _at->recv("OK");
00928             } else {
00929                 // Should never fail to do _at->send()/_at->recv()
00930                 success = false;
00931             }
00932             _at->debug_on(_debug_trace_on);
00933         } else if (timer.read_ms() < SOCKET_TIMEOUT) {
00934             // Wait for URCs
00935             _at->recv(UNNATURAL_STRING);
00936         } else {
00937             if (count == 0) {
00938                 // Timeout with nothing received
00939                 nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK;
00940                 success = false;
00941             }
00942             size = 0; // This simply to cause an exit
00943         }
00944 
00945         at_set_timeout(at_timeout);
00946         UNLOCK();
00947     }
00948     timer.stop();
00949 
00950     if (success) {
00951         nsapi_error_size = count;
00952     }
00953 
00954     if (_debug_trace_on) {
00955         tr_debug("socket_recvfrom: %d \"%*.*s\"", count, count, count, buf - count);
00956     } else {
00957         tr_debug("socket_recvfrom: received %d byte(s)", count);
00958     }
00959 
00960     return nsapi_error_size;
00961 }
00962 
00963 // Attach an event callback to a socket, required for asynchronous
00964 // data reception
00965 void UbloxATCellularInterface::socket_attach(nsapi_socket_t handle,
00966                                              void (*callback)(void *),
00967                                              void *data)
00968 {
00969     SockCtrl *socket = (SockCtrl *) handle;
00970 
00971     MBED_ASSERT (check_socket(socket));
00972 
00973     socket->callback = callback;
00974     socket->data = data;
00975 }
00976 
00977 // Unsupported TCP server functions.
00978 nsapi_error_t UbloxATCellularInterface::socket_listen(nsapi_socket_t handle,
00979                                                       int backlog)
00980 {
00981     return NSAPI_ERROR_UNSUPPORTED;
00982 }
00983 nsapi_error_t UbloxATCellularInterface::socket_accept(nsapi_socket_t server,
00984                                                       nsapi_socket_t *handle,
00985                                                       SocketAddress *address)
00986 {
00987     return NSAPI_ERROR_UNSUPPORTED;
00988 }
00989 
00990 // Unsupported option functions.
00991 nsapi_error_t UbloxATCellularInterface::setsockopt(nsapi_socket_t handle,
00992                                                    int level, int optname,
00993                                                    const void *optval,
00994                                                    unsigned optlen)
00995 {
00996     return NSAPI_ERROR_UNSUPPORTED;
00997 }
00998 nsapi_error_t UbloxATCellularInterface::getsockopt(nsapi_socket_t handle,
00999                                                    int level, int optname,
01000                                                    void *optval,
01001                                                    unsigned *optlen)
01002 {
01003     return NSAPI_ERROR_UNSUPPORTED;
01004 }
01005 
01006 /**********************************************************************
01007  * PUBLIC METHODS
01008  **********************************************************************/
01009 
01010 // Constructor.
01011 UbloxATCellularInterface::UbloxATCellularInterface(PinName tx,
01012                                                    PinName rx,
01013                                                    int baud,
01014                                                    bool debug_on,
01015                                                    osPriority priority)
01016 {
01017     _sim_pin_check_change_pending = false;
01018     _sim_pin_check_change_pending_enabled_value = false;
01019     _sim_pin_change_pending = false;
01020     _sim_pin_change_pending_new_pin_value = NULL;
01021     _run_event_thread = true;
01022     _apn = NULL;
01023     _uname = NULL;
01024     _pwd = NULL;
01025 
01026 
01027 
01028 
01029     // Initialise sockets storage
01030     memset(_sockets, 0, sizeof(_sockets));
01031     for (unsigned int socket = 0; socket < sizeof(_sockets) / sizeof(_sockets[0]); socket++) {
01032         _sockets[socket].modem_handle = SOCKET_UNUSED;
01033         _sockets[socket].callback = NULL;
01034         _sockets[socket].data = NULL;
01035     }
01036 
01037     // The authentication to use
01038     _auth = NSAPI_SECURITY_UNKNOWN;
01039 
01040     // Nullify the temporary IP address storage
01041     _ip = NULL;
01042     _connection_status_cb = NULL;
01043 
01044 
01045     // Initialise the base class, which starts the AT parser
01046     baseClassInit(tx, rx, baud, debug_on);
01047 
01048     // Start the event handler thread for Rx data
01049     event_thread.start(callback(this, &UbloxATCellularInterface::handle_event));
01050     event_thread.set_priority(priority);
01051 
01052     // URC handlers for sockets
01053     _at->oob("+UUSORD", callback(this, &UbloxATCellularInterface::UUSORD_URC));
01054     _at->oob("+UUSORF", callback(this, &UbloxATCellularInterface::UUSORF_URC));
01055     _at->oob("+UUSOCL", callback(this, &UbloxATCellularInterface::UUSOCL_URC));
01056     _at->oob("+UUPSDD", callback(this, &UbloxATCellularInterface::UUPSDD_URC));
01057 }
01058 
01059 // Destructor.
01060 UbloxATCellularInterface::~UbloxATCellularInterface()
01061 {
01062     // Let the event thread shut down tidily
01063     _run_event_thread = false;
01064     event_thread.join();
01065     
01066     // Free _ip if it was ever allocated
01067     free(_ip);
01068 }
01069 
01070 // Set the authentication scheme.
01071 void UbloxATCellularInterface::set_authentication(nsapi_security_t auth)
01072 {
01073     _auth = auth;
01074 }
01075 
01076 // Set APN, user name and password.
01077 void  UbloxATCellularInterface::set_credentials(const char *apn,
01078                                                 const char *uname,
01079                                                 const char *pwd)
01080 {
01081     _apn = apn;
01082     _uname = uname;
01083     _pwd = pwd;
01084 }
01085 
01086 // Set PIN.
01087 void UbloxATCellularInterface::set_sim_pin(const char *pin)
01088 {
01089     set_pin(pin);
01090 }
01091 
01092 // Get the IP address of a host.
01093 nsapi_error_t UbloxATCellularInterface::gethostbyname(const char *host,
01094                                                       SocketAddress *address,
01095                                                       nsapi_version_t version)
01096 {
01097     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
01098 
01099 
01100     if (address->set_ip_address(host)) {
01101         nsapi_error = NSAPI_ERROR_OK;
01102     } else {
01103         int at_timeout;
01104         char ipAddress[NSAPI_IP_SIZE];
01105         LOCK();
01106         // This interrogation can sometimes take longer than the usual 8 seconds
01107         at_timeout = _at_timeout;
01108         at_set_timeout(60000);
01109         memset (ipAddress, 0, sizeof (ipAddress)); // Ensure terminator
01110         if (_at->send("AT+UDNSRN=0,\"%s\"", host) &&
01111             _at->recv("+UDNSRN: \"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", ipAddress) &&
01112             _at->recv("OK")) {
01113             if (address->set_ip_address(ipAddress)) {
01114                 nsapi_error = NSAPI_ERROR_OK;
01115             }
01116         }
01117         at_set_timeout(at_timeout);
01118         UNLOCK();
01119     }
01120 
01121     return nsapi_error;
01122 }
01123 
01124 // Make a cellular connection
01125 nsapi_error_t UbloxATCellularInterface::connect(const char *sim_pin,
01126                                                 const char *apn,
01127                                                 const char *uname,
01128                                                 const char *pwd)
01129 {
01130     nsapi_error_t nsapi_error;
01131 
01132     if (sim_pin != NULL) {
01133         _pin = sim_pin;
01134     }
01135 
01136     if (apn != NULL) {
01137         _apn = apn;
01138     }
01139 
01140     if ((uname != NULL) && (pwd != NULL)) {
01141         _uname = uname;
01142         _pwd = pwd;
01143     } else {
01144         _uname = NULL;
01145         _pwd = NULL;
01146     }
01147 
01148     nsapi_error = connect();
01149 
01150     return nsapi_error;
01151 }
01152 
01153 // Make a cellular connection using the IP stack on board the cellular modem
01154 nsapi_error_t UbloxATCellularInterface::connect()
01155 {
01156     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
01157     bool registered = false;
01158 
01159     // Set up modem and then register with the network
01160     if (init()) {
01161         nsapi_error = NSAPI_ERROR_NO_CONNECTION;
01162         // Perform any pending SIM actions
01163         if (_sim_pin_check_change_pending) {
01164             if (!sim_pin_check_enable(_sim_pin_check_change_pending_enabled_value)) {
01165                 nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
01166             }
01167             _sim_pin_check_change_pending = false;
01168         }
01169         if (_sim_pin_change_pending) {
01170             if (!change_sim_pin(_sim_pin_change_pending_new_pin_value)) {
01171                 nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
01172             }
01173             _sim_pin_change_pending = false;
01174         }
01175 #ifdef TARGET_UBLOX_C030_R41XM
01176         define_context();
01177 #endif
01178         if (nsapi_error == NSAPI_ERROR_NO_CONNECTION) {
01179             for (int retries = 0; !registered && (retries < 3); retries++) {
01180                 if (nwk_registration()) {
01181                     registered = true;
01182 #ifdef TARGET_UBLOX_C030_R41XM
01183                     if (activate_context()) {
01184                         nsapi_error = NSAPI_ERROR_OK;
01185                     }
01186 #endif
01187                 }
01188             }
01189         }
01190     }
01191 #ifndef TARGET_UBLOX_C030_R41XM
01192     // Attempt to establish a connection
01193     if (registered && connect_modem_stack()) {
01194         nsapi_error = NSAPI_ERROR_OK;
01195     }
01196 #endif
01197     return nsapi_error;
01198 }
01199 
01200 // User initiated disconnect.
01201 nsapi_error_t UbloxATCellularInterface::disconnect()
01202 {
01203     nsapi_error_t nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
01204 #ifdef TARGET_UBLOX_C030_R41XM
01205     if (nwk_deregistration()) {
01206         if (_connection_status_cb) {
01207             _connection_status_cb(NSAPI_ERROR_CONNECTION_LOST);
01208         }
01209 #else
01210     if (disconnect_modem_stack() && nwk_deregistration()) {
01211 #endif
01212         nsapi_error = NSAPI_ERROR_OK;
01213     }
01214 
01215     return nsapi_error;
01216 }
01217 
01218 // Enable or disable SIM PIN check lock.
01219 nsapi_error_t UbloxATCellularInterface::set_sim_pin_check(bool set,
01220                                                           bool immediate,
01221                                                           const char *sim_pin)
01222 {
01223     nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
01224 
01225     if (sim_pin != NULL) {
01226         _pin = sim_pin;
01227     }
01228 
01229     if (immediate) {
01230         if (init()) {
01231             if (sim_pin_check_enable(set)) {
01232                 nsapi_error = NSAPI_ERROR_OK;
01233             }
01234         } else {
01235             nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
01236         }
01237     } else {
01238         nsapi_error = NSAPI_ERROR_OK;
01239         _sim_pin_check_change_pending = true;
01240         _sim_pin_check_change_pending_enabled_value = set;
01241     }
01242 
01243     return nsapi_error;
01244 }
01245 
01246 // Change the PIN code for the SIM card.
01247 nsapi_error_t UbloxATCellularInterface::set_new_sim_pin(const char *new_pin,
01248                                                         bool immediate,
01249                                                         const char *old_pin)
01250 {
01251     nsapi_error_t nsapi_error = NSAPI_ERROR_AUTH_FAILURE;
01252 
01253     if (old_pin != NULL) {
01254         _pin = old_pin;
01255     }
01256 
01257     if (immediate) {
01258         if (init()) {
01259             if (change_sim_pin(new_pin)) {
01260                 nsapi_error = NSAPI_ERROR_OK;
01261             }
01262         } else {
01263             nsapi_error = NSAPI_ERROR_DEVICE_ERROR;
01264         }
01265     } else {
01266         nsapi_error = NSAPI_ERROR_OK;
01267         _sim_pin_change_pending = true;
01268         _sim_pin_change_pending_new_pin_value = new_pin;
01269     }
01270 
01271     return nsapi_error;
01272 }
01273 
01274 // Determine if the connection is up.
01275 bool UbloxATCellularInterface::is_connected()
01276 {
01277     return get_ip_address() != NULL;
01278 }
01279 
01280 // Get the IP address of the on-board modem IP stack.
01281 const char * UbloxATCellularInterface::get_ip_address()
01282 {
01283     SocketAddress address;
01284     LOCK();
01285 
01286     if (_ip == NULL) {
01287         // Temporary storage for an IP address string with terminator
01288         _ip = (char *) malloc(NSAPI_IP_SIZE);
01289     }
01290 
01291     if (_ip != NULL) {
01292         memset(_ip, 0, NSAPI_IP_SIZE); // Ensure a terminator
01293         // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
01294         // If we get back a quoted "w.x.y.z" then we have an IP address,
01295         // otherwise we don't.
01296 #ifdef TARGET_UBLOX_C030_R41XM
01297         if (!_at->send("AT+CGPADDR=1") ||
01298             !_at->recv("+CGPADDR: 1,%" u_stringify(NSAPI_IP_SIZE) "[^\n]\nOK\n", _ip) ||
01299             !address.set_ip_address(_ip) || // Return NULL if the address is not a valid one
01300             !address) { // Return null if the address is zero
01301             free (_ip);
01302             _ip = NULL;
01303         }
01304 #else
01305         if (!_at->send("AT+UPSND=" PROFILE ",0") ||
01306             !_at->recv("+UPSND: " PROFILE ",0,\"%" u_stringify(NSAPI_IP_SIZE) "[^\"]\"", _ip) ||
01307             !_at->recv("OK") ||
01308             !address.set_ip_address(_ip) || // Return NULL if the address is not a valid one
01309             !address) { // Return null if the address is zero
01310             free (_ip);
01311             _ip = NULL;
01312         }
01313 #endif
01314     }
01315 
01316     UNLOCK();
01317     return _ip;
01318 }
01319 
01320 // Get the local network mask.
01321 const char *UbloxATCellularInterface::get_netmask()
01322 {
01323     // Not implemented.
01324     return NULL;
01325 }
01326 
01327 // Get the local gateways.
01328 const char *UbloxATCellularInterface::get_gateway()
01329 {
01330     return get_ip_address();
01331 }
01332 
01333 // Callback in case the connection is lost.
01334 void UbloxATCellularInterface::connection_status_cb(Callback<void(nsapi_error_t)> cb)
01335 {
01336     _connection_status_cb = cb;
01337 }
01338 
01339 void UbloxATCellularInterface::set_plmn(const char *plmn) {
01340 
01341 }
01342 
01343 // End of file
01344