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