fork

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