Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers QUECTEL_BC95_CellularStack.cpp Source File

QUECTEL_BC95_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 "rtos/ThisThread.h"
00019 #include "mbed_error.h"
00020 #include "platform/mbed_atomic.h"
00021 #include "events/EventQueue.h"
00022 #include "events/mbed_shared_queues.h"
00023 
00024 #include "QUECTEL_BC95_CellularStack.h"
00025 #include "CellularUtil.h"
00026 #include "CellularLog.h"
00027 
00028 #define PACKET_SIZE_MAX 1358
00029 #define TXFULL_EVENT_TIMEOUT (1 * 1000) // ms
00030 
00031 #define AT_UPLINK_BUSY          159
00032 #define AT_UART_BUFFER_ERROR    536
00033 #define AT_BACK_OFF_TIMER       537
00034 
00035 using namespace mbed;
00036 using namespace mbed_cellular_util;
00037 
00038 QUECTEL_BC95_CellularStack::QUECTEL_BC95_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type, AT_CellularDevice &device) :
00039     AT_CellularStack(atHandler, cid, stack_type, device), _event_queue(mbed_event_queue()), _txfull_event_id(0)
00040 {
00041     _at.set_urc_handler("+NSONMI:", mbed::Callback<void()>(this, &QUECTEL_BC95_CellularStack::urc_nsonmi));
00042     _at.set_urc_handler("+NSOCLI:", mbed::Callback<void()>(this, &QUECTEL_BC95_CellularStack::urc_nsocli));
00043 }
00044 
00045 QUECTEL_BC95_CellularStack::~QUECTEL_BC95_CellularStack()
00046 {
00047     if (_txfull_event_id) {
00048         _event_queue->cancel(_txfull_event_id);
00049     }
00050 
00051     _at.set_urc_handler("+NSONMI:", NULL);
00052     _at.set_urc_handler("+NSOCLI:", NULL);
00053 }
00054 
00055 nsapi_error_t QUECTEL_BC95_CellularStack::socket_listen(nsapi_socket_t handle, int backlog)
00056 {
00057     return NSAPI_ERROR_UNSUPPORTED ;
00058 }
00059 
00060 nsapi_error_t QUECTEL_BC95_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr)
00061 {
00062     return NSAPI_ERROR_UNSUPPORTED ;
00063 }
00064 
00065 nsapi_error_t QUECTEL_BC95_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &address)
00066 {
00067     CellularSocket *socket = (CellularSocket *)handle;
00068 
00069     _at.lock();
00070     if (socket->id == -1) {
00071         const nsapi_error_t error_create = create_socket_impl(socket);
00072         if (error_create != NSAPI_ERROR_OK ) {
00073             return error_create;
00074         }
00075     }
00076 
00077     _at.cmd_start("AT+NSOCO=");
00078     _at.write_int(socket->id);
00079     _at.write_string(address.get_ip_address(), false);
00080     _at.write_int(address.get_port());
00081     _at.cmd_stop_read_resp();
00082 
00083     _at.unlock();
00084 
00085     if (_at.get_last_error() == NSAPI_ERROR_OK ) {
00086         socket->remoteAddress = address;
00087         socket->connected = true;
00088         return NSAPI_ERROR_OK ;
00089     }
00090 
00091     return NSAPI_ERROR_NO_CONNECTION ;
00092 }
00093 
00094 void QUECTEL_BC95_CellularStack::urc_nsonmi()
00095 {
00096     int sock_id = _at.read_int();
00097 
00098     for (int i = 0; i < get_max_socket_count(); i++) {
00099         CellularSocket *sock = _socket[i];
00100         if (sock && sock->id == sock_id) {
00101             if (sock->_cb) {
00102                 sock->_cb(sock->_data);
00103             }
00104             break;
00105         }
00106     }
00107 }
00108 
00109 void QUECTEL_BC95_CellularStack::urc_nsocli()
00110 {
00111     int sock_id = _at.read_int();
00112 
00113     const nsapi_error_t err = _at.get_last_error();
00114 
00115     if (err != NSAPI_ERROR_OK ) {
00116         return;
00117     }
00118 
00119     CellularSocket *sock = find_socket(sock_id);
00120 
00121     if (sock) {
00122         sock->closed = true;
00123         if (sock->_cb) {
00124             sock->_cb(sock->_data);
00125         }
00126         tr_info("Socket closed %d", sock_id);
00127     }
00128 }
00129 
00130 
00131 int QUECTEL_BC95_CellularStack::get_max_socket_count()
00132 {
00133     return BC95_SOCKET_MAX;
00134 }
00135 
00136 bool QUECTEL_BC95_CellularStack::is_protocol_supported(nsapi_protocol_t protocol)
00137 {
00138     return (protocol == NSAPI_UDP  || protocol == NSAPI_TCP );
00139 }
00140 
00141 nsapi_error_t QUECTEL_BC95_CellularStack::socket_close_impl(int sock_id)
00142 {
00143     CellularSocket *sock = find_socket(sock_id);
00144 
00145     if (sock && sock->closed) {
00146         return NSAPI_ERROR_OK ;
00147     }
00148 
00149     sock->txfull_event = false;
00150 
00151     nsapi_error_t err = _at.at_cmd_discard("+NSOCL", "=", "%d", sock_id);
00152 
00153     tr_info("Close socket: %d error: %d", sock_id, err);
00154 
00155     return err;
00156 }
00157 
00158 nsapi_error_t QUECTEL_BC95_CellularStack::create_socket_impl(CellularSocket *socket)
00159 {
00160     int sock_id = -1;
00161     bool socketOpenWorking = false;
00162 
00163     if (socket->proto == NSAPI_UDP ) {
00164         _at.cmd_start_stop("+NSOCR", "=DGRAM,", "%d%d%d%s", 17, socket->localAddress.get_port(), 1, ((_ip_ver_sendto == NSAPI_IPv4 ) ? "AF_INET" : "AF_INET6"));
00165     } else if (socket->proto == NSAPI_TCP ) {
00166         _at.cmd_start_stop("+NSOCR", "=STREAM,", "%d%d%d%s", 6, socket->localAddress.get_port(), 1, ((_ip_ver_sendto == NSAPI_IPv4 ) ? "AF_INET" : "AF_INET6"));
00167     } else {
00168         return NSAPI_ERROR_PARAMETER ;
00169     }
00170     _at.resp_start();
00171     sock_id = _at.read_int();
00172     _at.resp_stop();
00173 
00174     socketOpenWorking = (_at.get_last_error() == NSAPI_ERROR_OK );
00175 
00176     if (!socketOpenWorking || (sock_id == -1)) {
00177         tr_error("Socket create failed!");
00178         return NSAPI_ERROR_NO_SOCKET ;
00179     }
00180 
00181     tr_info("Socket create id: %d", sock_id);
00182 
00183     socket->id = sock_id;
00184 
00185     return NSAPI_ERROR_OK ;
00186 }
00187 
00188 nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
00189                                                                      const void *data, nsapi_size_t size)
00190 {
00191     //AT_CellularStack::socket_sendto(...) will create a socket on modem if it wasn't
00192     // open already.
00193     MBED_ASSERT(socket->id != -1);
00194 
00195     if (_ip_ver_sendto != address.get_ip_version()) {
00196         _ip_ver_sendto =  address.get_ip_version();
00197         socket_close_impl(socket->id);
00198         create_socket_impl(socket);
00199     }
00200 
00201     int sent_len = 0;
00202 
00203     if (size > PACKET_SIZE_MAX) {
00204         return NSAPI_ERROR_PARAMETER ;
00205     }
00206 
00207     int retry = 0;
00208 retry_send:
00209     if (socket->proto == NSAPI_UDP ) {
00210         _at.cmd_start("AT+NSOST=");
00211         _at.write_int(socket->id);
00212         _at.write_string(address.get_ip_address(), false);
00213         _at.write_int(address.get_port());
00214         _at.write_int(size);
00215     } else if (socket->proto == NSAPI_TCP ) {
00216         _at.cmd_start("AT+NSOSD=");
00217         _at.write_int(socket->id);
00218         _at.write_int(size);
00219     } else {
00220         return NSAPI_ERROR_PARAMETER ;
00221     }
00222 
00223     _at.write_hex_string((char *)data, size);
00224     _at.cmd_stop();
00225     _at.resp_start();
00226     // skip socket id
00227     _at.skip_param();
00228     sent_len = _at.read_int();
00229     _at.resp_stop();
00230 
00231     if (_at.get_last_error() == NSAPI_ERROR_OK ) {
00232         return sent_len;
00233     }
00234 
00235     // check for network congestion
00236     device_err_t err = _at.get_last_device_error();
00237     if (err.errType == DeviceErrorTypeErrorCME &&
00238             (err.errCode == AT_UART_BUFFER_ERROR || err.errCode == AT_BACK_OFF_TIMER) || err.errCode == AT_UPLINK_BUSY) {
00239         if (socket->proto == NSAPI_UDP ) {
00240             if (retry < 3) {
00241                 retry++;
00242                 tr_warn("Socket %d sendto EAGAIN", socket->id);
00243                 rtos::ThisThread::sleep_for(30);
00244                 _at.clear_error();
00245                 goto retry_send;
00246             }
00247             return NSAPI_ERROR_NO_MEMORY ;
00248         }
00249         _socket_mutex.lock();
00250         if (!socket->txfull_event && !_txfull_event_id) {
00251             tr_warn("socket %d tx full", socket->id);
00252             socket->txfull_event = true;
00253             _txfull_event_id = _event_queue->call_in(TXFULL_EVENT_TIMEOUT, callback(this, &QUECTEL_BC95_CellularStack::txfull_event_timeout));
00254             if (!_txfull_event_id) {
00255                 MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
00256                            "QUECTEL_BC95_CellularStack::socket_sendto_impl(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
00257                 _socket_mutex.unlock();
00258                 return NSAPI_ERROR_NO_MEMORY ;
00259             }
00260         }
00261         _socket_mutex.unlock();
00262         return NSAPI_ERROR_WOULD_BLOCK ;
00263     }
00264 
00265     return _at.get_last_error();
00266 }
00267 
00268 nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
00269                                                                        void *buffer, nsapi_size_t size)
00270 {
00271     //AT_CellularStack::socket_recvfrom(...) will create a socket on modem if it wasn't
00272     // open already.
00273     MBED_ASSERT(socket->id != -1);
00274 
00275     nsapi_size_or_error_t recv_len = 0;
00276     int port;
00277     char ip_address[NSAPI_IP_SIZE];
00278 
00279     _at.cmd_start_stop("+NSORF", "=", "%d%d", socket->id, size < PACKET_SIZE_MAX ? size : PACKET_SIZE_MAX);
00280 
00281     _at.resp_start();
00282     // receiving socket id
00283     _at.skip_param();
00284     _at.read_string(ip_address, sizeof(ip_address));
00285     port = _at.read_int();
00286     recv_len = _at.read_int();
00287     int hexlen = _at.read_hex_string((char *)buffer, recv_len);
00288     // remaining length
00289     _at.skip_param();
00290     _at.resp_stop();
00291 
00292     if (!recv_len || (recv_len == -1) || (_at.get_last_error() != NSAPI_ERROR_OK )) {
00293         return NSAPI_ERROR_WOULD_BLOCK ;
00294     }
00295 
00296     if (address) {
00297         address->set_ip_address(ip_address);
00298         address->set_port(port);
00299     }
00300 
00301     if (recv_len != hexlen) {
00302         tr_error("Not received as much data as expected. Should receive: %d bytes, received: %d bytes", recv_len, hexlen);
00303     }
00304     return recv_len;
00305 }
00306 
00307 void QUECTEL_BC95_CellularStack::txfull_event_timeout()
00308 {
00309     _socket_mutex.lock();
00310     _txfull_event_id = 0;
00311     for (int i = 0; i < get_max_socket_count(); i++) {
00312         CellularSocket *sock = _socket[i];
00313         if (sock && sock->_cb && sock->txfull_event) {
00314             sock->txfull_event = false;
00315             sock->_cb(sock->_data);
00316         }
00317     }
00318     _socket_mutex.unlock();
00319 }