Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AT_CellularStack.cpp Source File

AT_CellularStack.cpp

00001 /*
00002  * Copyright (c) 2017, 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 "AT_CellularStack.h"
00019 #include "CellularUtil.h"
00020 #include "CellularLog.h"
00021 #include "ThisThread.h"
00022 #include "AT_CellularDevice.h"
00023 
00024 using namespace mbed_cellular_util;
00025 using namespace mbed;
00026 
00027 AT_CellularStack::AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type, AT_CellularDevice &device) :
00028     _socket(NULL), _socket_count(0), _cid(cid),
00029     _stack_type(stack_type), _ip_ver_sendto(NSAPI_UNSPEC ), _at(at), _device(device)
00030 {
00031     memset(_ip, 0, PDP_IPV6_SIZE);
00032 }
00033 
00034 AT_CellularStack::~AT_CellularStack()
00035 {
00036     for (int i = 0; i < _socket_count; i++) {
00037         if (_socket[i]) {
00038             delete _socket[i];
00039             _socket[i] = NULL;
00040         }
00041     }
00042     _socket_count = 0;
00043 
00044     delete [] _socket;
00045     _socket = NULL;
00046 }
00047 
00048 int AT_CellularStack::find_socket_index(nsapi_socket_t handle)
00049 {
00050     int max_socket_count = get_max_socket_count();
00051     for (int i = 0; i < max_socket_count; i++) {
00052         if (_socket[i] == handle) {
00053             return i;
00054         }
00055     }
00056     return -1;
00057 }
00058 
00059 /** NetworkStack
00060  */
00061 nsapi_error_t AT_CellularStack::get_ip_address(SocketAddress *address)
00062 {
00063     if (!address) {
00064         return NSAPI_ERROR_PARAMETER ;
00065     }
00066     _at.lock();
00067 
00068     bool ipv4 = false, ipv6 = false;
00069 
00070     _at.cmd_start_stop("+CGPADDR", "=", "%d", _cid);
00071     _at.resp_start("+CGPADDR:");
00072 
00073     if (_at.info_resp()) {
00074         _at.skip_param();
00075 
00076         if (_at.read_string(_ip, PDP_IPV6_SIZE) != -1) {
00077             convert_ipv6(_ip);
00078             address->set_ip_address(_ip);
00079 
00080             ipv4 = (address->get_ip_version() == NSAPI_IPv4 );
00081             ipv6 = (address->get_ip_version() == NSAPI_IPv6 );
00082 
00083             // Try to look for second address ONLY if modem has support for dual stack(can handle both IPv4 and IPv6 simultaneously).
00084             // Otherwise assumption is that second address is not reliable, even if network provides one.
00085             if ((_device.get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) && (_at.read_string(_ip, PDP_IPV6_SIZE) != -1))) {
00086                 convert_ipv6(_ip);
00087                 address->set_ip_address(_ip);
00088                 ipv6 = (address->get_ip_version() == NSAPI_IPv6 );
00089             }
00090         }
00091     }
00092     _at.resp_stop();
00093     _at.unlock();
00094 
00095     if (ipv4 && ipv6) {
00096         _stack_type = IPV4V6_STACK;
00097     } else if (ipv4) {
00098         _stack_type = IPV4_STACK;
00099     } else if (ipv6) {
00100         _stack_type = IPV6_STACK;
00101     }
00102 
00103     return (ipv4 || ipv6) ? NSAPI_ERROR_OK  : NSAPI_ERROR_NO_ADDRESS ;
00104 }
00105 
00106 const char *AT_CellularStack::get_ip_address()
00107 {
00108     _at.lock();
00109 
00110     bool ipv4 = false, ipv6 = false;
00111 
00112     _at.cmd_start_stop("+CGPADDR", "=", "%d", _cid);
00113     _at.resp_start("+CGPADDR:");
00114 
00115     if (_at.info_resp()) {
00116         _at.skip_param();
00117 
00118         if (_at.read_string(_ip, PDP_IPV6_SIZE) != -1) {
00119             convert_ipv6(_ip);
00120             SocketAddress address;
00121             address.set_ip_address(_ip);
00122 
00123             ipv4 = (address.get_ip_version() == NSAPI_IPv4 );
00124             ipv6 = (address.get_ip_version() == NSAPI_IPv6 );
00125 
00126             // Try to look for second address ONLY if modem has support for dual stack(can handle both IPv4 and IPv6 simultaneously).
00127             // Otherwise assumption is that second address is not reliable, even if network provides one.
00128             if ((_device.get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) && (_at.read_string(_ip, PDP_IPV6_SIZE) != -1))) {
00129                 convert_ipv6(_ip);
00130                 address.set_ip_address(_ip);
00131                 ipv6 = (address.get_ip_version() == NSAPI_IPv6 );
00132             }
00133         }
00134     }
00135     _at.resp_stop();
00136     _at.unlock();
00137 
00138     if (ipv4 && ipv6) {
00139         _stack_type = IPV4V6_STACK;
00140     } else if (ipv4) {
00141         _stack_type = IPV4_STACK;
00142     } else if (ipv6) {
00143         _stack_type = IPV6_STACK;
00144     }
00145 
00146     return (ipv4 || ipv6) ? _ip : NULL;
00147 }
00148 
00149 void AT_CellularStack::set_cid(int cid)
00150 {
00151     _cid = cid;
00152 }
00153 
00154 nsapi_error_t AT_CellularStack::socket_stack_init()
00155 {
00156     return NSAPI_ERROR_OK ;
00157 }
00158 
00159 nsapi_error_t AT_CellularStack::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
00160 {
00161     if (!is_protocol_supported(proto) || !handle) {
00162         return NSAPI_ERROR_UNSUPPORTED ;
00163     }
00164 
00165     int max_socket_count = get_max_socket_count();
00166 
00167     _socket_mutex.lock();
00168 
00169     if (!_socket) {
00170         if (socket_stack_init() != NSAPI_ERROR_OK ) {
00171             _socket_mutex.unlock();
00172             return NSAPI_ERROR_NO_SOCKET ;
00173         }
00174 
00175         _socket = new CellularSocket*[max_socket_count];
00176         _socket_count = max_socket_count;
00177         for (int i = 0; i < max_socket_count; i++) {
00178             _socket[i] = 0;
00179         }
00180     }
00181 
00182     int index = find_socket_index(0);
00183     if (index == -1) {
00184         tr_error("No free sockets!");
00185         _socket_mutex.unlock();
00186         return NSAPI_ERROR_NO_SOCKET ;
00187     }
00188 
00189     tr_info("Socket %d open", index);
00190     // create local socket structure, socket on modem is created when app calls sendto/recvfrom
00191     // Do not assign a socket ID yet. Socket is not created at the Modem yet.
00192     // create_socket_impl(handle) will assign the correct socket ID.
00193     _socket[index] = new CellularSocket;
00194     CellularSocket *psock = _socket[index];
00195     SocketAddress addr(0, get_dynamic_ip_port());
00196 
00197     psock->localAddress = addr;
00198     psock->proto = proto;
00199     *handle = psock;
00200 
00201     _socket_mutex.unlock();
00202 
00203     return NSAPI_ERROR_OK ;
00204 }
00205 
00206 nsapi_error_t AT_CellularStack::socket_close(nsapi_socket_t handle)
00207 {
00208     int err = NSAPI_ERROR_DEVICE_ERROR ;
00209 
00210     struct CellularSocket *socket = (struct CellularSocket *)handle;
00211     if (!socket) {
00212         return NSAPI_ERROR_NO_SOCKET ;
00213     }
00214     int sock_id = socket->id;
00215 
00216     int index = find_socket_index(handle);
00217     if (index == -1) {
00218         tr_error("No socket found to be closed");
00219         return err;
00220     }
00221 
00222     err = NSAPI_ERROR_OK ;
00223 
00224     // Close the socket on the modem if it was created
00225     _at.lock();
00226     if (sock_id > -1) {
00227         err = socket_close_impl(sock_id);
00228     }
00229 
00230     if (!err) {
00231         tr_info("Socket %d closed", index);
00232     } else {
00233         tr_info("Socket %d close (id %d, started %d, error %d)", index, sock_id, socket->started, err);
00234     }
00235 
00236     _socket_mutex.lock();
00237     _socket[index] = NULL;
00238     delete socket;
00239     _socket_mutex.unlock();
00240 
00241     _at.unlock();
00242 
00243     return err;
00244 }
00245 
00246 nsapi_error_t AT_CellularStack::socket_bind(nsapi_socket_t handle, const SocketAddress &addr)
00247 {
00248     struct CellularSocket *socket = (CellularSocket *)handle;
00249     if (!socket) {
00250         return NSAPI_ERROR_NO_SOCKET ;
00251     }
00252 
00253     if (addr) {
00254         return NSAPI_ERROR_UNSUPPORTED ;
00255     }
00256 
00257     _at.lock();
00258 
00259     uint16_t port = addr.get_port();
00260     if (port != socket->localAddress.get_port()) {
00261         if (port && (get_socket_index_by_port(port) == -1)) {
00262             socket->localAddress.set_port(port);
00263         } else {
00264             _at.unlock();
00265             return NSAPI_ERROR_PARAMETER ;
00266         }
00267     }
00268 
00269     if (socket->id == -1) {
00270         create_socket_impl(socket);
00271     }
00272 
00273     return _at.unlock_return_error();
00274 }
00275 
00276 nsapi_error_t AT_CellularStack::socket_listen(nsapi_socket_t handle, int backlog)
00277 {
00278     return NSAPI_ERROR_UNSUPPORTED ;
00279 }
00280 
00281 nsapi_error_t AT_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &addr)
00282 {
00283     CellularSocket *socket = (CellularSocket *)handle;
00284     if (!socket) {
00285         return NSAPI_ERROR_NO_SOCKET ;
00286     }
00287     socket->remoteAddress = addr;
00288     socket->connected = true;
00289 
00290     return NSAPI_ERROR_OK ;
00291 }
00292 
00293 nsapi_error_t AT_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr)
00294 {
00295     return NSAPI_ERROR_UNSUPPORTED ;
00296 }
00297 
00298 nsapi_size_or_error_t AT_CellularStack::socket_send(nsapi_socket_t handle, const void *data, unsigned size)
00299 {
00300     CellularSocket *socket = (CellularSocket *)handle;
00301     if (!socket) {
00302         return NSAPI_ERROR_NO_SOCKET ;
00303     }
00304     if (!socket->connected) {
00305         return NSAPI_ERROR_NO_CONNECTION ;
00306     }
00307     return socket_sendto(handle, socket->remoteAddress, data, size);
00308 }
00309 
00310 nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, const SocketAddress &addr, const void *data, unsigned size)
00311 {
00312     CellularSocket *socket = (CellularSocket *)handle;
00313     if (!socket) {
00314         return NSAPI_ERROR_NO_SOCKET ;
00315     }
00316 
00317     if (socket->closed && !socket->pending_bytes) {
00318         tr_info("sendto socket %d closed", socket->id);
00319         return NSAPI_ERROR_NO_CONNECTION ;
00320     }
00321 
00322     if (size == 0) {
00323         if (socket->proto == NSAPI_UDP ) {
00324             return NSAPI_ERROR_UNSUPPORTED ;
00325         } else if (socket->proto == NSAPI_TCP ) {
00326             return 0;
00327         }
00328     }
00329 
00330     nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK ;
00331 
00332     if (socket->id == -1) {
00333 
00334         /* Check that stack type supports sendto address type*/
00335         if (!is_addr_stack_compatible(addr)) {
00336             return NSAPI_ERROR_PARAMETER ;
00337         }
00338 
00339         _ip_ver_sendto = addr.get_ip_version();
00340         _at.lock();
00341 
00342         ret_val = create_socket_impl(socket);
00343 
00344         _at.unlock();
00345         if (ret_val != NSAPI_ERROR_OK ) {
00346             tr_error("Socket %d create %s error %d", find_socket_index(socket), addr.get_ip_address(), ret_val);
00347             return ret_val;
00348         }
00349     }
00350 
00351     /* Check parameters - sendto address is valid and stack type supports sending to that address type*/
00352     if (!is_addr_stack_compatible(addr)) {
00353         return NSAPI_ERROR_PARAMETER ;
00354     }
00355 
00356     _at.lock();
00357 
00358     ret_val = socket_sendto_impl(socket, addr, data, size);
00359 
00360     _at.unlock();
00361 
00362     if (ret_val >= 0) {
00363         tr_info("Socket %d sent %d bytes to %s port %d", find_socket_index(socket), ret_val, addr.get_ip_address(), addr.get_port());
00364     } else if (ret_val != NSAPI_ERROR_WOULD_BLOCK ) {
00365         tr_error("Socket %d sendto %s error %d", find_socket_index(socket), addr.get_ip_address(), ret_val);
00366     }
00367 
00368     return ret_val;
00369 }
00370 
00371 nsapi_size_or_error_t AT_CellularStack::socket_recv(nsapi_socket_t handle, void *data, unsigned size)
00372 {
00373     return socket_recvfrom(handle, NULL, data, size);
00374 }
00375 
00376 nsapi_size_or_error_t AT_CellularStack::socket_recvfrom(nsapi_socket_t handle, SocketAddress *addr, void *buffer, unsigned size)
00377 {
00378     CellularSocket *socket = (CellularSocket *)handle;
00379     if (!socket) {
00380         return NSAPI_ERROR_NO_SOCKET ;
00381     }
00382 
00383     if (socket->closed) {
00384         tr_info("recvfrom socket %d closed", socket->id);
00385         return 0;
00386     }
00387 
00388     nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK ;
00389 
00390     if (socket->id == -1) {
00391         _at.lock();
00392 
00393         ret_val = create_socket_impl(socket);
00394 
00395         _at.unlock();
00396         if (ret_val != NSAPI_ERROR_OK ) {
00397             tr_error("Socket %d create error %d", find_socket_index(socket), ret_val);
00398             return ret_val;
00399         }
00400     }
00401 
00402     _at.lock();
00403 
00404     ret_val = socket_recvfrom_impl(socket, addr, buffer, size);
00405 
00406     _at.unlock();
00407 
00408     if (socket->closed) {
00409         tr_info("recvfrom socket %d closed", socket->id);
00410         return 0;
00411     }
00412 
00413     if (ret_val >= 0) {
00414         if (addr) {
00415             tr_info("Socket %d recv %d bytes from %s port %d", find_socket_index(socket), ret_val, addr->get_ip_address(), addr->get_port());
00416         } else {
00417             tr_info("Socket %d recv %d bytes", find_socket_index(socket), ret_val);
00418         }
00419     } else if (ret_val != NSAPI_ERROR_WOULD_BLOCK ) {
00420         tr_error("Socket %d recv error %d", find_socket_index(socket), ret_val);
00421     }
00422 
00423     return ret_val;
00424 }
00425 
00426 void AT_CellularStack::socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data)
00427 {
00428     CellularSocket *socket = (CellularSocket *)handle;
00429     if (!socket) {
00430         return;
00431     }
00432     socket->_cb = callback;
00433     socket->_data = data;
00434 }
00435 
00436 int AT_CellularStack::get_socket_index_by_port(uint16_t port)
00437 {
00438     int max_socket_count = get_max_socket_count();
00439     for (int i = 0; i < max_socket_count; i++) {
00440         if (_socket[i]->localAddress.get_port() == port) {
00441             return i;
00442         }
00443     }
00444     return -1;
00445 }
00446 
00447 AT_CellularStack::CellularSocket *AT_CellularStack::find_socket(int sock_id)
00448 {
00449     CellularSocket *sock = NULL;
00450     for (int i = 0; i < _socket_count; i++) {
00451         if (_socket[i] && _socket[i]->id == sock_id) {
00452             sock = _socket[i];
00453             break;
00454         }
00455     }
00456     if (!sock) {
00457         tr_error("Socket not found %d", sock_id);
00458     }
00459     return sock;
00460 }
00461 
00462 bool AT_CellularStack::is_addr_stack_compatible(const SocketAddress &addr)
00463 {
00464     if ((addr.get_ip_version() == NSAPI_UNSPEC ) ||
00465             (addr.get_ip_version() == NSAPI_IPv4  && _stack_type == IPV6_STACK) ||
00466             (addr.get_ip_version() == NSAPI_IPv6  && _stack_type == IPV4_STACK)) {
00467         return false;
00468     }
00469     return true;
00470 }
00471