takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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