Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UBLOX_AT_CellularStack.cpp Source File

UBLOX_AT_CellularStack.cpp

00001 /*
00002  * Copyright (c) 2018, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "UBLOX_AT_CellularStack.h"
00019 #include "mbed_poll.h"
00020 
00021 using namespace mbed;
00022 using namespace mbed_cellular_util;
00023 
00024 UBLOX_AT_CellularStack::UBLOX_AT_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type, AT_CellularDevice &device) :
00025     AT_CellularStack(atHandler, cid, stack_type, device)
00026 {
00027     // URC handlers for sockets
00028     _at.set_urc_handler("+UUSORD:", callback(this, &UBLOX_AT_CellularStack::UUSORD_URC));
00029     _at.set_urc_handler("+UUSORF:", callback(this, &UBLOX_AT_CellularStack::UUSORF_URC));
00030     _at.set_urc_handler("+UUSOCL:", callback(this, &UBLOX_AT_CellularStack::UUSOCL_URC));
00031     _at.set_urc_handler("+UUPSDD:", callback(this, &UBLOX_AT_CellularStack::UUPSDD_URC));
00032 }
00033 
00034 UBLOX_AT_CellularStack::~UBLOX_AT_CellularStack()
00035 {
00036 }
00037 
00038 nsapi_error_t UBLOX_AT_CellularStack::socket_listen(nsapi_socket_t handle, int backlog)
00039 {
00040     return NSAPI_ERROR_UNSUPPORTED ;
00041 }
00042 
00043 nsapi_error_t UBLOX_AT_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr)
00044 {
00045     return NSAPI_ERROR_UNSUPPORTED ;
00046 }
00047 
00048 // Callback for Socket Read URC.
00049 void UBLOX_AT_CellularStack::UUSORD_URC()
00050 {
00051     int a, b;
00052     CellularSocket *socket;
00053 
00054     a = _at.read_int();
00055     b = _at.read_int();
00056 
00057     socket = find_socket(a);
00058     if (socket != NULL) {
00059         socket->pending_bytes = b;
00060         // No debug prints here as they can affect timing
00061         // and cause data loss in UARTSerial
00062         if (socket->_cb != NULL) {
00063             socket->_cb(socket->_data);
00064         }
00065     }
00066 }
00067 
00068 // Callback for Socket Read From URC.
00069 void UBLOX_AT_CellularStack::UUSORF_URC()
00070 {
00071     int a, b;
00072     CellularSocket *socket;
00073 
00074     a = _at.read_int();
00075     b = _at.read_int();
00076 
00077     socket = find_socket(a);
00078     if (socket != NULL) {
00079         socket->pending_bytes = b;
00080         // No debug prints here as they can affect timing
00081         // and cause data loss in UARTSerial
00082         if (socket->_cb != NULL) {
00083             socket->_cb(socket->_data);
00084         }
00085     }
00086 }
00087 
00088 // Callback for Socket Close URC.
00089 void UBLOX_AT_CellularStack::UUSOCL_URC()
00090 {
00091     int a;
00092     CellularSocket *socket;
00093 
00094     a = _at.read_int();
00095     socket = find_socket(a);
00096     clear_socket(socket);
00097 }
00098 
00099 // Callback for UUPSDD.
00100 void UBLOX_AT_CellularStack::UUPSDD_URC()
00101 {
00102     int a;
00103     CellularSocket *socket;
00104 
00105     a = _at.read_int();
00106     socket = find_socket(a);
00107     clear_socket(socket);
00108 }
00109 
00110 int UBLOX_AT_CellularStack::get_max_socket_count()
00111 {
00112     return UBLOX_MAX_SOCKET;
00113 }
00114 
00115 bool UBLOX_AT_CellularStack::is_protocol_supported(nsapi_protocol_t protocol)
00116 {
00117     return (protocol == NSAPI_UDP  || protocol == NSAPI_TCP );
00118 }
00119 
00120 nsapi_error_t UBLOX_AT_CellularStack::create_socket_impl(CellularSocket *socket)
00121 {
00122     int sock_id = SOCKET_UNUSED;
00123 
00124     nsapi_error_t err = NSAPI_ERROR_OK ;
00125     if (socket->proto == NSAPI_UDP ) {
00126         err = _at.at_cmd_int("+USOCR", "=17", sock_id);
00127     } else if (socket->proto == NSAPI_TCP ) {
00128         err = _at.at_cmd_int("+USOCR", "=6", sock_id);
00129     } // Unsupported protocol is checked in "is_protocol_supported" function
00130 
00131     if ((err != NSAPI_ERROR_OK ) || (sock_id == -1)) {
00132         return NSAPI_ERROR_NO_SOCKET ;
00133     }
00134 
00135     // Check for duplicate socket id delivered by modem
00136     for (int i = 0; i < UBLOX_MAX_SOCKET; i++) {
00137         CellularSocket *sock = _socket[i];
00138         if (sock && sock != socket && sock->id == sock_id) {
00139             return NSAPI_ERROR_NO_SOCKET ;
00140         }
00141     }
00142 
00143     socket->started = true;
00144     socket->id = sock_id;
00145 
00146     return err;
00147 }
00148 
00149 nsapi_error_t UBLOX_AT_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &addr)
00150 {
00151     CellularSocket *socket = (CellularSocket *)handle;
00152 
00153     if (socket) {
00154         if (socket->id == SOCKET_UNUSED) {
00155             nsapi_error_t err = create_socket_impl(socket);
00156             if (err != NSAPI_ERROR_OK ) {
00157                 return err;
00158             }
00159         }
00160     } else {
00161         return NSAPI_ERROR_DEVICE_ERROR ;
00162     }
00163 
00164     nsapi_error_t err = _at.at_cmd_discard("+USOCO", "=", "%d%s%d", socket->id, addr.get_ip_address(), addr.get_port());
00165 
00166     if (err == NSAPI_ERROR_OK ) {
00167         socket->remoteAddress = addr;
00168         socket->connected = true;
00169         return NSAPI_ERROR_OK ;
00170     }
00171 
00172     return NSAPI_ERROR_NO_CONNECTION ;
00173 }
00174 
00175 nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
00176                                                                  const void *data, nsapi_size_t size)
00177 {
00178     MBED_ASSERT(socket->id != -1);
00179 
00180     int sent_len = 0;
00181     pollfh fhs;
00182     fhs.fh = _at.get_file_handle();
00183     fhs.events = POLLIN;
00184 
00185     if (socket->proto == NSAPI_UDP ) {
00186         if (size > UBLOX_MAX_PACKET_SIZE) {
00187             return NSAPI_ERROR_PARAMETER ;
00188         }
00189         _at.cmd_start_stop("+USOST", "=", "%d%s%d%d", socket->id, address.get_ip_address(), address.get_port(), size);
00190 
00191         (void)poll(&fhs, 1, 50);
00192         _at.write_bytes((uint8_t *)data, size);
00193 
00194         _at.resp_start("+USOST:");
00195         _at.skip_param(); // skip socket id
00196         sent_len = _at.read_int();
00197         _at.resp_stop();
00198 
00199         if ((_at.get_last_error() == NSAPI_ERROR_OK )) {
00200             return sent_len;
00201         }
00202     } else if (socket->proto == NSAPI_TCP ) {
00203         bool success = true;
00204         const char *buf = (const char *) data;
00205         nsapi_size_t blk = UBLOX_MAX_PACKET_SIZE;
00206         nsapi_size_t count = size;
00207 
00208         while ((count > 0) && success) {
00209             if (count < blk) {
00210                 blk = count;
00211             }
00212             _at.cmd_start_stop("+USOWR", "=", "%d%d", socket->id, blk);
00213 
00214             (void)poll(&fhs, 1, 50);
00215             _at.write_bytes((uint8_t *)buf, blk);
00216 
00217             _at.resp_start("+USOWR:");
00218             _at.skip_param(); // skip socket id
00219             sent_len = _at.read_int();
00220             _at.resp_stop();
00221 
00222             if ((sent_len >= (int) blk) &&
00223                     (_at.get_last_error() == NSAPI_ERROR_OK )) {
00224             } else {
00225                 success = false;
00226             }
00227 
00228             buf += blk;
00229             count -= blk;
00230         }
00231 
00232         if (success && _at.get_last_error() == NSAPI_ERROR_OK ) {
00233             return size - count;
00234         }
00235     }
00236 
00237     return _at.get_last_error();
00238 }
00239 
00240 nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
00241                                                                    void *buffer, nsapi_size_t size)
00242 {
00243     MBED_ASSERT(socket->id != -1);
00244 
00245     nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR ;
00246     bool success = true;
00247     nsapi_size_t read_blk;
00248     nsapi_size_t count = 0;
00249     nsapi_size_t usorf_sz;
00250     char ipAddress[NSAPI_IP_SIZE];
00251     uint8_t ch = 0;
00252     int port = 0;
00253     Timer timer;
00254 
00255     if (socket->pending_bytes == 0) {
00256         _at.process_oob();
00257         if (socket->pending_bytes == 0) {
00258             return NSAPI_ERROR_WOULD_BLOCK ;
00259         }
00260     }
00261 
00262     timer.start();
00263     if (socket->proto == NSAPI_UDP ) {
00264         while (success && (size > 0)) {
00265             read_blk = UBLOX_MAX_PACKET_SIZE;
00266             if (read_blk > size) {
00267                 read_blk = size;
00268             }
00269             if (socket->pending_bytes > 0) {
00270                 _at.cmd_start_stop("+USORF", "=", "%d%d", socket->id, read_blk);
00271 
00272                 _at.resp_start("+USORF:");
00273                 _at.skip_param(); // receiving socket id
00274                 _at.read_string(ipAddress, sizeof(ipAddress));
00275                 port = _at.read_int();
00276                 usorf_sz = _at.read_int();
00277                 if (usorf_sz > size) {
00278                     usorf_sz = size;
00279                 }
00280                 _at.read_bytes(&ch, 1);
00281                 _at.read_bytes((uint8_t *)buffer + count, usorf_sz);
00282                 _at.resp_stop();
00283 
00284                 // Must use what +USORF returns here as it may be less or more than we asked for
00285                 if (usorf_sz > socket->pending_bytes) {
00286                     socket->pending_bytes = 0;
00287                 } else {
00288                     socket->pending_bytes -= usorf_sz;
00289                 }
00290 
00291                 if (usorf_sz > 0) {
00292                     count += usorf_sz;
00293                     size -= usorf_sz;
00294                 } else {
00295                     // read() should not fail
00296                     success = false;
00297                 }
00298             }  else if (timer.read_ms() < SOCKET_TIMEOUT) {
00299                 // Wait for URCs
00300                 _at.process_oob();
00301             } else {
00302                 if (count == 0) {
00303                     // Timeout with nothing received
00304                     success = false;
00305                 }
00306                 break;
00307             }
00308         }
00309     } else if (socket->proto == NSAPI_TCP ) {
00310         while (success && (size > 0)) {
00311             read_blk = UBLOX_MAX_PACKET_SIZE;
00312             if (read_blk > size) {
00313                 read_blk = size;
00314             }
00315             if (socket->pending_bytes > 0) {
00316                 _at.cmd_start_stop("+USORD", "=", "%d%d", socket->id, read_blk);
00317 
00318                 _at.resp_start("+USORD:");
00319                 _at.skip_param(); // receiving socket id
00320                 usorf_sz = _at.read_int();
00321                 if (usorf_sz > size) {
00322                     usorf_sz = size;
00323                 }
00324                 _at.read_bytes(&ch, 1);
00325                 _at.read_bytes((uint8_t *)buffer + count, usorf_sz);
00326                 _at.resp_stop();
00327 
00328                 // Must use what +USORD returns here as it may be less or more than we asked for
00329                 if (usorf_sz > socket->pending_bytes) {
00330                     socket->pending_bytes = 0;
00331                 } else {
00332                     socket->pending_bytes -= usorf_sz;
00333                 }
00334 
00335                 if (usorf_sz > 0) {
00336                     count += usorf_sz;
00337                     size -= usorf_sz;
00338                 } else {
00339                     success = false;
00340                 }
00341             } else if (timer.read_ms() < SOCKET_TIMEOUT) {
00342                 // Wait for URCs
00343                 _at.process_oob();
00344             } else {
00345                 if (count == 0) {
00346                     // Timeout with nothing received
00347                     success = false;
00348                 }
00349                 break;
00350             }
00351         }
00352     }
00353     timer.stop();
00354 
00355     socket->pending_bytes = 0;
00356     if (!count || (_at.get_last_error() != NSAPI_ERROR_OK )) {
00357         return NSAPI_ERROR_WOULD_BLOCK ;
00358     } else {
00359         nsapi_error_size = count;
00360     }
00361 
00362     if (success && socket->proto == NSAPI_UDP  && address) {
00363         address->set_ip_address(ipAddress);
00364         address->get_ip_address();
00365         address->set_port(port);
00366     }
00367 
00368     return nsapi_error_size;
00369 }
00370 
00371 nsapi_error_t UBLOX_AT_CellularStack::socket_close_impl(int sock_id)
00372 {
00373     return _at.at_cmd_discard("+USOCL", "=", "%d", sock_id);
00374 }
00375 
00376 // Find or create a socket from the list.
00377 UBLOX_AT_CellularStack::CellularSocket *UBLOX_AT_CellularStack::find_socket(int id)
00378 {
00379     CellularSocket *socket = NULL;
00380 
00381     for (unsigned int x = 0; (socket == NULL) && (x < UBLOX_MAX_SOCKET); x++) {
00382         if (_socket) {
00383             if (_socket[x]->id == id) {
00384                 socket = (_socket[x]);
00385             }
00386         }
00387     }
00388 
00389     return socket;
00390 }
00391 
00392 
00393 // Clear out the storage for a socket
00394 void UBLOX_AT_CellularStack::clear_socket(CellularSocket *socket)
00395 {
00396     if (socket != NULL) {
00397         socket->id = SOCKET_UNUSED;
00398         socket->started = false;
00399         socket->pending_bytes = 0;
00400         socket->closed = true;
00401         if (socket->_cb) {
00402             socket->_cb(socket->_data);
00403         }
00404     }
00405 }
00406 
00407 const char *UBLOX_AT_CellularStack::get_ip_address()
00408 {
00409     _at.lock();
00410     _at.cmd_start_stop("+UPSND", "=", "%d%d", PROFILE, 0);
00411 
00412     _at.resp_start("+UPSND:");
00413     if (_at.info_resp()) {
00414         _at.skip_param();
00415         _at.skip_param();
00416         int len = _at.read_string(_ip, NSAPI_IPv4_SIZE);
00417         if (len == -1) {
00418             _ip[0] = '\0';
00419             _at.unlock();
00420             // no IPV4 address, return
00421             return NULL;
00422         }
00423 
00424         // in case stack type is not IPV4 only, try to look also for IPV6 address
00425         if (_stack_type != IPV4_STACK) {
00426             len = _at.read_string(_ip, PDP_IPV6_SIZE);
00427         }
00428     }
00429     _at.resp_stop();
00430     _at.unlock();
00431 
00432     // we have at least IPV4 address
00433     convert_ipv6(_ip);
00434 
00435     return _ip;
00436 }
00437 
00438 nsapi_error_t UBLOX_AT_CellularStack::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version, const char *interface_name)
00439 {
00440     char ipAddress[NSAPI_IP_SIZE];
00441     nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION ;
00442 
00443     _at.lock();
00444     if (address->set_ip_address(host)) {
00445         err = NSAPI_ERROR_OK ;
00446     } else {
00447 #ifdef UBX_MDM_SARA_R41XM
00448         _at.set_at_timeout(70000);
00449 #else
00450         _at.set_at_timeout(120000);
00451 #endif
00452         // This interrogation can sometimes take longer than the usual 8 seconds
00453         _at.cmd_start_stop("+UDNSRN", "=0,", "%s", host);
00454 
00455         _at.resp_start("+UDNSRN:");
00456         if (_at.info_resp()) {
00457             _at.read_string(ipAddress, sizeof(ipAddress));
00458 
00459             if (address->set_ip_address(ipAddress)) {
00460                 err = NSAPI_ERROR_OK ;
00461             }
00462         }
00463         _at.resp_stop();
00464         _at.restore_at_timeout();
00465     }
00466     _at.unlock();
00467 
00468     return err;
00469 }