Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 }
Generated on Tue Jul 12 2022 13:54:46 by
