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.
BG96Interface.cpp
00001 /** 00002 * copyright (c) 2018, James Flynn 00003 * SPDX-License-Identifier: Apache-2.0 00004 */ 00005 00006 /* 00007 * Licensed under the Apache License, Version 2.0 (the "License"); 00008 * you may not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, 00015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * 00017 * See the License for the specific language governing permissions and 00018 * limitations under the License. 00019 * 00020 */ 00021 00022 /**---------------------------------------------------------- 00023 * @file BG96Interface.cpp 00024 * @brief BG96 NetworkInterfaceAPI implementation for Mbed OS v5.x 00025 * 00026 * @author James Flynn 00027 * 00028 * @date 1-April-2018 00029 */ 00030 00031 #include <ctype.h> 00032 #include "mbed.h" 00033 #include "BG96.h" 00034 #include "BG96Interface.h" 00035 00036 // 00037 // The driver uses a simple/basic state machine to manage receiving and transmitting 00038 // data. These are the states that are used 00039 // 00040 #define READ_INIT 10 //initialize for a read state 00041 #define READ_START 11 //start reading from the BG96 00042 #define READ_ACTIVE 12 //a read is on-going/active 00043 #define READ_DOCB 13 //need to perform a call-back on the socket 00044 #define DATA_AVAILABLE 14 //indicates that rx data is available 00045 00046 #define TX_IDLE 20 //indicates that no data is bing TX'd 00047 #define TX_STARTING 21 //indicates that TX data is starting 00048 #define TX_ACTIVE 22 //indicates that TX data is being sent 00049 #define TX_COMPLETE 23 //all TX data has been sent 00050 #define TX_DOCB 24 //indicatew we need to exeucte the call-back 00051 00052 #define BG96_READ_TIMEOUTMS 30000 //read timeout in MS 00053 #define EQ_FREQ 50 //frequency in ms to check for Tx/Rx data 00054 #define EQ_FREQ_SLOW 2000 //frequency in ms to check when in slow monitor mode 00055 00056 #define EVENT_COMPLETE 0 //signals when a TX/RX event is complete 00057 #define EVENT_GETMORE 0x01 //signals when we need additional TX/RX data 00058 00059 // 00060 // The following are only used when debug is eabled. 00061 // 00062 00063 #if MBED_CONF_APP_BG96_DEBUG == true 00064 #define debugOutput(...) _dbOut(__VA_ARGS__) 00065 #define debugDump_arry(...) _dbDump_arry(__VA_ARGS__) 00066 00067 #define dbgIO_lock dbgout_mutex.lock(); //used to prevent stdio output over-writes 00068 #define dbgIO_unlock dbgout_mutex.unlock(); //when executing--including BG96 debug output 00069 00070 /** functions to output debug data--------------------------- 00071 * 00072 * @author James Flynn 00073 * @param data pointer to the data array to dump 00074 * @param size number of bytes to dump 00075 * @return void 00076 * @date 1-Feb-2018 00077 */ 00078 00079 00080 void BG96Interface::_dbDump_arry( const uint8_t* data, unsigned int size ) 00081 { 00082 unsigned int i, k; 00083 00084 dbgIO_lock; 00085 if( g_debug & DBGMSG_ARRY ) { 00086 for (i=0; i<size; i+=16) { 00087 printf("[BG96 Driver]:0x%04X: ",i); 00088 for (k=0; k<16; k++) { 00089 if( (i+k)<size ) 00090 printf("%02X ", data[i+k]); 00091 else 00092 printf(" "); 00093 } 00094 printf(" "); 00095 for (k=0; k<16; k++) { 00096 if( (i+k)<size ) 00097 printf("%c", isprint(data[i+k])? data[i+k]:'.'); 00098 } 00099 printf("\n\r"); 00100 } 00101 } 00102 dbgIO_unlock; 00103 } 00104 00105 void BG96Interface::_dbOut(int who, const char* format, ...) 00106 { 00107 char buffer[256]; 00108 dbgIO_lock; 00109 if( who & (g_debug & (DBGMSG_DRV|DBGMSG_EQ)) ) { 00110 va_list args; 00111 va_start (args, format); 00112 printf("[BG96 Driver]: "); 00113 vsnprintf(buffer, sizeof(buffer), format, args); 00114 printf("%s",buffer); 00115 printf("\n"); 00116 va_end (args); 00117 } 00118 dbgIO_unlock; 00119 } 00120 00121 #else 00122 00123 #define dbgIO_lock 00124 #define dbgIO_unlock 00125 #define debugOutput(...) {/* __VA_ARGS__ */} 00126 #define debugDump_arry(...) {/* __VA_ARGS__ */} 00127 00128 #endif //MBED_CONF_APP_BG96_DEBUG == true 00129 00130 00131 /** -------------------------------------------------------- 00132 * @brief BG96Interface constructor 00133 * @param none 00134 * @retval none 00135 */ 00136 BG96Interface::BG96Interface(void) : 00137 g_isInitialized(NSAPI_ERROR_NO_CONNECTION), 00138 g_bg96_queue_id(-1), 00139 scheduled_events(0), 00140 _BG96(false) 00141 { 00142 for( int i=0; i<BG96_SOCKET_COUNT; i++ ) { 00143 g_sock[i].id = -1; 00144 g_sock[i].disTO = false; 00145 g_sock[i].connected = false; 00146 g_socRx[i].m_rx_state = READ_START; 00147 g_socRx[i].m_rx_disTO = false; 00148 g_socTx[i].m_tx_state = TX_IDLE; 00149 } 00150 #if MBED_CONF_APP_BG96_DEBUG == true 00151 g_debug=0; 00152 #endif 00153 } 00154 00155 /** ---------------------------------------------------------- 00156 * @brief BG96Interface destructor 00157 * @param none 00158 * @retval none 00159 */ 00160 BG96Interface::~BG96Interface() 00161 { 00162 } 00163 00164 /** ---------------------------------------------------------- 00165 * @brief network connect 00166 * connects to Access Point, can be called with no argument 00167 * or arguments. If none, use default APN. 00168 * @param ap: Access Point Name (APN) Name String 00169 * pass_word: Password String for AP 00170 * username: username to use for AP 00171 * @retval NSAPI Error Type 00172 */ 00173 nsapi_error_t BG96Interface::connect(void) 00174 { 00175 nsapi_error_t ret = NSAPI_ERROR_OK; 00176 debugOutput(DBGMSG_DRV,"BG96Interface::connect(void) ENTER."); 00177 if( g_isInitialized == NSAPI_ERROR_NO_CONNECTION ) 00178 ret = connect(DEFAULT_APN, NULL, NULL); 00179 00180 return (ret == NSAPI_ERROR_NO_CONNECTION); 00181 } 00182 00183 nsapi_error_t BG96Interface::connect(const char *apn, const char *username, const char *password) 00184 { 00185 Timer t; 00186 bool ok=false; 00187 00188 debugOutput(DBGMSG_DRV,"BG96Interface::connect(%s,%s,%s) ENTER",apn,username,password); 00189 00190 if( g_isInitialized == NSAPI_ERROR_IS_CONNECTED ) 00191 ok = disconnect(); 00192 00193 t.start(); 00194 dbgIO_lock; 00195 while(t.read_ms() < BG96_MISC_TIMEOUT && !ok) 00196 ok = _BG96.startup(); 00197 dbgIO_unlock; 00198 00199 if( ok && g_bg96_queue_id == -1) 00200 g_bg96_queue_id = _bg96_monitor.start(callback(&_bg96_queue, &EventQueue::dispatch_forever)); 00201 00202 debugOutput(DBGMSG_DRV,"BG96Interface::connect EXIT"); 00203 00204 return ok? set_credentials(apn, username, password) : NSAPI_ERROR_DEVICE_ERROR; 00205 } 00206 00207 /** Set the cellular network credentials -------------------- 00208 * 00209 * @param apn Optional, APN of network 00210 * @param user Optional, username --not used-- 00211 * @param pass Optional, password --not used-- 00212 * @return nsapi_error_t 00213 */ 00214 nsapi_error_t BG96Interface::set_credentials(const char *apn, const char *username, const char *password) 00215 { 00216 debugOutput(DBGMSG_DRV,"BG96Interface::set_credentials ENTER/EXIT, APN=%s, USER=%s, PASS=%s",apn,username,password); 00217 g_isInitialized = (_BG96.connect((char*)apn, (char*)username, (char*)password)==true)? NSAPI_ERROR_NO_CONNECTION : NSAPI_ERROR_IS_CONNECTED; 00218 00219 return g_isInitialized; 00220 } 00221 00222 /**---------------------------------------------------------- 00223 * @brief network disconnect 00224 * disconnects from APN 00225 * @param none 00226 * @return nsapi_error_t 00227 */ 00228 int BG96Interface::disconnect(void) 00229 { 00230 nsapi_error_t ret; 00231 00232 debugOutput(DBGMSG_DRV,"BG96Interface::disconnect ENTER"); 00233 _bg96_queue.cancel(g_bg96_queue_id); 00234 g_bg96_queue_id = -1; 00235 g_isInitialized = NSAPI_ERROR_NO_CONNECTION; 00236 dbgIO_lock; 00237 ret = _BG96.disconnect(); 00238 dbgIO_unlock; 00239 debugOutput(DBGMSG_DRV,"BG96Interface::disconnect EXIT"); 00240 return ret? NSAPI_ERROR_OK:NSAPI_ERROR_DEVICE_ERROR; 00241 } 00242 00243 /**---------------------------------------------------------- 00244 * @brief Get the local IP address 00245 * @param none 00246 * @retval Null-terminated representation of the local IP address 00247 * or null if not yet connected 00248 */ 00249 const char *BG96Interface::get_ip_address() 00250 { 00251 static char ip[25]; 00252 debugOutput(DBGMSG_DRV,"BG96Interface::get_ip_address ENTER"); 00253 dbgIO_lock; 00254 const char* ptr = _BG96.getIPAddress(ip); 00255 dbgIO_unlock; 00256 00257 debugOutput(DBGMSG_DRV,"BG96Interface::get_ip_address EXIT"); 00258 return ptr; 00259 } 00260 00261 /**---------------------------------------------------------- 00262 * @brief Get the MAC address 00263 * @param none 00264 * @retval Null-terminated representation of the MAC address 00265 * or null if not yet connected 00266 */ 00267 const char *BG96Interface::get_mac_address() 00268 { 00269 static char mac[25]; 00270 debugOutput(DBGMSG_DRV,"BG96Interface::get_mac_address ENTER"); 00271 dbgIO_lock; 00272 const char* ptr = _BG96.getMACAddress(mac); 00273 dbgIO_unlock; 00274 debugOutput(DBGMSG_DRV,"BG96Interface::get_mac_address EXIT"); 00275 return ptr; 00276 } 00277 00278 /**---------------------------------------------------------- 00279 * @brief Get Module Firmware Information 00280 * @param none 00281 * @retval Null-terminated representation of the MAC address 00282 * or null if error 00283 */ 00284 const char* BG96Interface::getRevision(void) 00285 { 00286 static char str[40]; 00287 dbgIO_lock; 00288 const char* ptr = _BG96.getRev(str); 00289 dbgIO_unlock; 00290 return ptr; 00291 } 00292 00293 /**---------------------------------------------------------- 00294 * @brief attach function/callback to the socket 00295 * Not used 00296 * @param handle: Pointer to handle 00297 * callback: callback function pointer 00298 * data: pointer to data 00299 * @retval none 00300 */ 00301 void BG96Interface::socket_attach(void *handle, void (*callback)(void *), void *data) 00302 { 00303 BG96SOCKET *sock = (BG96SOCKET*)handle; 00304 debugOutput(DBGMSG_DRV,"ENTER/EXIT socket_attach(), socket %d attached",sock->id); 00305 sock->_callback = callback; 00306 sock->_data = data; 00307 } 00308 00309 00310 /**---------------------------------------------------------- 00311 * @brief bind to a port number and address 00312 * @param handle: Pointer to socket handle 00313 * proto: address to bind to 00314 * @return nsapi_error_t 00315 */ 00316 int BG96Interface::socket_bind(void *handle, const SocketAddress &address) 00317 { 00318 debugOutput(DBGMSG_DRV,"BG96Interface::socket_bind ENTER/EXIT"); 00319 return socket_listen(handle, 1); 00320 } 00321 00322 /**---------------------------------------------------------- 00323 * @brief start listening on a port and address 00324 * @param handle: Pointer to handle 00325 * backlog: not used (always value is 1) 00326 * @return nsapi_error_t 00327 */ 00328 int BG96Interface::socket_listen(void *handle, int backlog) 00329 { 00330 BG96SOCKET *socket = (BG96SOCKET *)handle; 00331 nsapi_error_t ret = NSAPI_ERROR_OK; 00332 00333 backlog = backlog; //avoid unused error from compiler 00334 debugOutput(DBGMSG_DRV,"BG96Interface::socket_listen, socket %d listening %s ENTER", 00335 socket->id, socket->connected? "YES":"NO"); 00336 if( !socket->connected ) { 00337 socket->disTO = true; 00338 _eq_schedule(); 00339 } 00340 else 00341 ret = NSAPI_ERROR_NO_CONNECTION; 00342 00343 debugOutput(DBGMSG_DRV,"BG96Interface::socket_listen EXIT"); 00344 return ret; 00345 } 00346 00347 /**---------------------------------------------------------- 00348 * @brief Set the socket options 00349 * Not used 00350 * @param handle: Pointer to handle 00351 * level: SOL_SOCKET 00352 * optname: option name 00353 * optval: pointer to option value 00354 * optlen: option length 00355 * @return nsapi_error_t 00356 */ 00357 int BG96Interface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) 00358 { 00359 BG96SOCKET *sock = (BG96SOCKET *)handle; 00360 00361 debugOutput(DBGMSG_DRV,"BG96Interface::setsockopt ENTER/EXIT"); 00362 if (!optlen || !sock) { 00363 return NSAPI_ERROR_PARAMETER; 00364 } 00365 00366 if (level == NSAPI_SOCKET && sock->proto == NSAPI_TCP) { 00367 switch (optname) { 00368 case NSAPI_REUSEADDR: 00369 case NSAPI_KEEPIDLE: 00370 case NSAPI_KEEPINTVL: 00371 case NSAPI_LINGER: 00372 case NSAPI_SNDBUF: 00373 case NSAPI_ADD_MEMBERSHIP: 00374 case NSAPI_DROP_MEMBERSHIP: 00375 case NSAPI_KEEPALIVE: 00376 return NSAPI_ERROR_UNSUPPORTED; 00377 00378 case NSAPI_RCVBUF: 00379 if (optlen == sizeof(void *)) { 00380 sock->dptr_last = (void*)optval; 00381 sock->dptr_size = (unsigned)optlen; 00382 return NSAPI_ERROR_OK; 00383 } 00384 return NSAPI_ERROR_PARAMETER; 00385 } 00386 } 00387 return NSAPI_ERROR_UNSUPPORTED; 00388 } 00389 00390 /**---------------------------------------------------------- 00391 * @brief Get the socket options 00392 * Not used 00393 * @param handle: Pointer to handle 00394 * level: SOL_SOCKET 00395 * optname: option name 00396 * optval: pointer to option value 00397 * optlen: pointer to option length 00398 * @return nsapi_error_t 00399 */ 00400 int BG96Interface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) 00401 { 00402 BG96SOCKET *sock = (BG96SOCKET *)handle; 00403 00404 debugOutput(DBGMSG_DRV,"BG96Interface::getsockopt ENTER/EXIT"); 00405 if (!optval || !optlen || !sock) { 00406 return NSAPI_ERROR_PARAMETER; 00407 } 00408 00409 if (level == NSAPI_SOCKET && sock->proto == NSAPI_TCP) { 00410 switch (optname) { 00411 case NSAPI_REUSEADDR: 00412 case NSAPI_KEEPALIVE: 00413 case NSAPI_KEEPIDLE: 00414 case NSAPI_KEEPINTVL: 00415 case NSAPI_LINGER: 00416 case NSAPI_SNDBUF: 00417 case NSAPI_ADD_MEMBERSHIP: 00418 case NSAPI_DROP_MEMBERSHIP: 00419 return NSAPI_ERROR_UNSUPPORTED; 00420 00421 case NSAPI_RCVBUF: 00422 optval = sock->dptr_last; 00423 *optlen = sock->dptr_size; 00424 return NSAPI_ERROR_OK; 00425 } 00426 } 00427 return NSAPI_ERROR_UNSUPPORTED; 00428 } 00429 00430 /**---------------------------------------------------------- 00431 * @brief helpe function to set debug levels. Only enabled 00432 * if debug flag set during compilation 00433 * @param int = value to set debug flag to 00434 * @retval none 00435 */ 00436 void BG96Interface::doDebug( int v ) 00437 { 00438 #if MBED_CONF_APP_BG96_DEBUG == true 00439 gvupdate_mutex.lock(); 00440 _BG96.doDebug(v); 00441 g_debug= v; 00442 gvupdate_mutex.unlock(); 00443 debugOutput(DBGMSG_DRV,"SET debug flag to 0x%02X",v); 00444 #endif 00445 } 00446 00447 /**---------------------------------------------------------- 00448 * @brief open a socket handle 00449 * @param handle: Pointer to handle 00450 * proto: TCP/UDP protocol 00451 * @return nsapi_error_t 00452 */ 00453 int BG96Interface::socket_open(void **handle, nsapi_protocol_t proto) 00454 { 00455 int i; 00456 nsapi_error_t ret=NSAPI_ERROR_OK; 00457 00458 debugOutput(DBGMSG_DRV,"ENTER socket_open(), protocol=%s", (proto==NSAPI_TCP)?"TCP":"UDP"); 00459 gvupdate_mutex.lock(); 00460 for( i=0; i<BG96_SOCKET_COUNT; i++ ) //find the next available socket... 00461 if( g_sock[i].id == -1 ) 00462 break; 00463 00464 if( i == BG96_SOCKET_COUNT ) { 00465 ret = NSAPI_ERROR_NO_SOCKET; 00466 debugOutput(DBGMSG_DRV,"EXIT socket_open; NO SOCKET AVAILABLE (%d)",i); 00467 } 00468 else{ 00469 debugOutput(DBGMSG_DRV,"socket_open using socket %d", i); 00470 00471 g_socTx[i].m_tx_state = TX_IDLE; 00472 g_socRx[i].m_rx_state = READ_START; 00473 00474 g_sock[i].id = i; 00475 g_sock[i].disTO = false; 00476 g_sock[i].proto = proto; 00477 g_sock[i].connected = false; 00478 g_sock[i]._callback = NULL; 00479 g_sock[i]._data = NULL; 00480 *handle = &g_sock[i]; 00481 debugOutput(DBGMSG_DRV,"EXIT socket_open; Socket=%d, protocol =%s", 00482 i, (g_sock[i].proto==NSAPI_UDP)?"UDP":"TCP"); 00483 } 00484 gvupdate_mutex.unlock(); 00485 00486 return ret; 00487 } 00488 00489 /**---------------------------------------------------------- 00490 * @brief close a socket 00491 * @param handle: Pointer to handle 00492 * @return nsapi_error_t 00493 */ 00494 int BG96Interface::socket_close(void *handle) 00495 { 00496 BG96SOCKET *sock = (BG96SOCKET*)handle; 00497 nsapi_error_t ret =NSAPI_ERROR_DEVICE_ERROR; 00498 RXEVENT *rxsock; 00499 TXEVENT *txsock; 00500 int i = sock->id; 00501 00502 debugOutput(DBGMSG_DRV,"ENTER socket_close(); Socket=%d", i); 00503 00504 if(i >= 0) { 00505 txrx_mutex.lock(); 00506 txsock = &g_socTx[i]; 00507 rxsock = &g_socRx[i]; 00508 00509 txsock->m_tx_state = TX_IDLE; 00510 rxsock->m_rx_state = READ_START; 00511 00512 dbgIO_lock; 00513 if( sock->connected ) 00514 _BG96.close(sock->id); 00515 dbgIO_unlock; 00516 00517 sock->id = -1; 00518 sock->disTO = false; 00519 sock->proto = NSAPI_TCP; 00520 sock->connected= false; 00521 sock->_callback= NULL; 00522 sock->_data = NULL; 00523 ret = NSAPI_ERROR_OK; 00524 txrx_mutex.unlock(); 00525 debugOutput(DBGMSG_DRV,"EXIT socket_close(), socket %d - success",i); 00526 } 00527 else 00528 debugOutput(DBGMSG_DRV,"EXIT socket_close() - fail"); 00529 return ret; 00530 } 00531 00532 /**---------------------------------------------------------- 00533 * @brief accept connections from remote sockets 00534 * @param handle: Pointer to handle of client socket (connecting) 00535 * proto: handle of server socket which will accept connections 00536 * @return nsapi_error_t 00537 */ 00538 int BG96Interface::socket_accept(nsapi_socket_t server,nsapi_socket_t *handle, SocketAddress *address) 00539 { 00540 return NSAPI_ERROR_UNSUPPORTED; 00541 } 00542 00543 /**---------------------------------------------------------- 00544 * @brief connect to a remote socket 00545 * @param handle: Pointer to socket handle 00546 * addr: Address to connect to 00547 * @return nsapi_error_t 00548 */ 00549 int BG96Interface::socket_connect(void *handle, const SocketAddress &addr) 00550 { 00551 BG96SOCKET *sock = (BG96SOCKET *)handle; 00552 nsapi_error_t ret=NSAPI_ERROR_OK; 00553 const char proto = (sock->proto == NSAPI_UDP) ? 'u' : 't'; 00554 bool k; 00555 int cnt; 00556 00557 00558 debugOutput(DBGMSG_DRV,"ENTER socket_connect(); Socket=%d; IP=%s; PORT=%d;", 00559 sock->id, addr.get_ip_address(), addr.get_port()); 00560 dbgIO_lock; 00561 for( k=true, cnt=0; cnt<3 && k; cnt++ ) { 00562 k = !_BG96.open(proto, sock->id, addr.get_ip_address(), addr.get_port()); 00563 if( k ) 00564 _BG96.close(sock->id); 00565 } 00566 dbgIO_unlock; 00567 00568 if( cnt<3 ) { 00569 sock->addr = addr; 00570 sock->connected = true; 00571 00572 if( sock->_callback != NULL ) 00573 sock->_callback(sock->_data); 00574 } 00575 else 00576 ret = NSAPI_ERROR_DEVICE_ERROR; 00577 00578 debugOutput(DBGMSG_DRV,"EXIT socket_connect(), Socket %d",sock->id); 00579 return ret; 00580 } 00581 00582 /**---------------------------------------------------------- 00583 * @brief return the address of this object 00584 * @param none 00585 * @retval pointer to this class object 00586 */ 00587 NetworkStack *BG96Interface::get_stack() 00588 { 00589 return this; 00590 } 00591 00592 /**---------------------------------------------------------- 00593 * @brief return IP address after looking up the URL name 00594 * @param name = URL string 00595 * address = address to store IP in 00596 * version = not used 00597 * @return nsapi_error_t 00598 */ 00599 nsapi_error_t BG96Interface::gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version) 00600 { 00601 char ipstr[25]; 00602 bool ok; 00603 nsapi_error_t ret=NSAPI_ERROR_OK; 00604 00605 debugOutput(DBGMSG_DRV,"ENTER gethostbyname(); IP=%s; PORT=%d; URL=%s;", 00606 address->get_ip_address(), address->get_port(), name); 00607 00608 dbgIO_lock; 00609 ok=_BG96.resolveUrl(name,ipstr); 00610 dbgIO_unlock; 00611 00612 if( !ok ) { 00613 ret = NSAPI_ERROR_DEVICE_ERROR; 00614 debugOutput(DBGMSG_DRV,"EXIT gethostbyname() -- failed to get DNS"); 00615 } 00616 else{ 00617 address->set_ip_address(ipstr); 00618 debugOutput(DBGMSG_DRV,"EXIT gethostbyname(); IP=%s; PORT=%d; URL=%s;", 00619 address->get_ip_address(), address->get_port(), name); 00620 } 00621 return ret; 00622 } 00623 00624 /**---------------------------------------------------------- 00625 * @brief send data to a udp socket 00626 * @param handle: Pointer to handle 00627 * addr: address of udp socket 00628 * data: pointer to data 00629 * size: size of data 00630 * @retval no of bytes sent 00631 */ 00632 int BG96Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) 00633 { 00634 BG96SOCKET *sock = (BG96SOCKET *)handle; 00635 int err=NSAPI_ERROR_OK; 00636 00637 if (!sock->connected) 00638 err = socket_connect(sock, addr); 00639 00640 if( err != NSAPI_ERROR_OK ) 00641 return err; 00642 else 00643 return socket_send(sock, data, size); 00644 } 00645 00646 00647 /**---------------------------------------------------------- 00648 * @brief write to a socket 00649 * @param handle: Pointer to handle 00650 * data: pointer to data 00651 * size: size of data 00652 * @retval no of bytes sent 00653 */ 00654 int BG96Interface::socket_send(void *handle, const void *data, unsigned size) 00655 { 00656 BG96SOCKET *sock = (BG96SOCKET *)handle; 00657 TXEVENT *txsock; 00658 00659 debugOutput(DBGMSG_DRV,"ENTER socket_send(),socket %d, send %d bytes",sock->id,size); 00660 00661 if( size < 1 || data == NULL ) // should never happen but have seen it 00662 return 0; 00663 00664 txrx_mutex.lock(); 00665 txsock = &g_socTx[sock->id]; 00666 00667 switch( txsock->m_tx_state ) { 00668 case TX_IDLE: 00669 txsock->m_tx_socketID = sock->id; 00670 txsock->m_tx_state = TX_STARTING; 00671 txsock->m_tx_dptr = (uint8_t*)data; 00672 txsock->m_tx_orig_size = size; 00673 txsock->m_tx_req_size = (uint32_t)size; 00674 txsock->m_tx_total_sent= 0; 00675 txsock->m_tx_callback = sock->_callback; 00676 txsock->m_tx_cb_data = sock->_data; 00677 debugDump_arry((const uint8_t*)data,size); 00678 00679 if( txsock->m_tx_req_size > BG96::BG96_BUFF_SIZE ) 00680 txsock->m_tx_req_size= BG96::BG96_BUFF_SIZE; 00681 00682 if( tx_event(txsock) != EVENT_COMPLETE ) { //if we didn't sent all the data, schedule background send the rest 00683 debugOutput(DBGMSG_DRV,"Schedule TX event for socket %d",sock->id); 00684 txsock->m_tx_state = TX_ACTIVE; 00685 _eq_schedule(); 00686 txrx_mutex.unlock(); 00687 return NSAPI_ERROR_WOULD_BLOCK; 00688 } 00689 // fall through 00690 00691 if( txsock->m_tx_state == TX_DOCB ) { 00692 debugOutput(DBGMSG_DRV,"Call socket %d TX call-back",sock->id); 00693 txsock->m_tx_state = TX_COMPLETE; 00694 txsock->m_tx_callback( txsock->m_tx_cb_data ); 00695 } 00696 00697 // fall through 00698 00699 case TX_COMPLETE: 00700 debugOutput(DBGMSG_DRV,"EXIT socket_send(), socket %d, sent %d bytes", txsock->m_tx_socketID,txsock->m_tx_total_sent); 00701 txsock->m_tx_state = TX_IDLE; 00702 txrx_mutex.unlock(); 00703 return txsock->m_tx_total_sent; 00704 00705 case TX_ACTIVE: 00706 case TX_STARTING: 00707 debugOutput(DBGMSG_DRV,"EXIT socket_send(), TX_ACTIVE/TX_STARTING"); 00708 txrx_mutex.unlock(); 00709 return NSAPI_ERROR_WOULD_BLOCK; 00710 00711 case TX_DOCB: 00712 default: 00713 debugOutput(DBGMSG_DRV,"EXIT socket_send(), NSAPI_ERROR_DEVICE_ERROR"); 00714 txrx_mutex.unlock(); 00715 return NSAPI_ERROR_DEVICE_ERROR; 00716 } 00717 } 00718 00719 /**---------------------------------------------------------- 00720 * @brief receive data on a udp socket 00721 * @param handle: Pointer to handle 00722 * addr: address of udp socket 00723 * data: pointer to data 00724 * size: size of data 00725 * @retval no of bytes read 00726 */ 00727 int BG96Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) 00728 { 00729 BG96SOCKET *sock = (BG96SOCKET *)handle; 00730 00731 if (!sock->connected) 00732 return NSAPI_ERROR_NO_CONNECTION; 00733 *addr = sock->addr; 00734 return socket_recv(sock, data, size); 00735 } 00736 00737 /**---------------------------------------------------------- 00738 * @brief receive data on a socket 00739 * @param handle: Pointer to socket handle 00740 * data: pointer to data 00741 * size: size of data 00742 * @retval no of bytes read 00743 */ 00744 int BG96Interface::socket_recv(void *handle, void *data, unsigned size) 00745 { 00746 BG96SOCKET *sock = (BG96SOCKET *)handle; 00747 RXEVENT *rxsock; 00748 00749 if( size < 1 || data == NULL ) // should never happen 00750 return 0; 00751 00752 txrx_mutex.lock(); 00753 rxsock = &g_socRx[sock->id]; 00754 debugOutput(DBGMSG_DRV,"ENTER socket_recv(), socket %d, request %d bytes",sock->id, size); 00755 00756 switch( rxsock->m_rx_state ) { 00757 case READ_START: //need to start a read sequence of events 00758 rxsock->m_rx_disTO = sock->disTO; 00759 rxsock->m_rx_socketID = sock->id; 00760 rxsock->m_rx_state = READ_INIT; 00761 rxsock->m_rx_dptr = (uint8_t*)data; 00762 rxsock->m_rx_req_size = (uint32_t)size; 00763 rxsock->m_rx_total_cnt = 0; 00764 rxsock->m_rx_timer = 0; 00765 rxsock->m_rx_return_cnt= 0; 00766 00767 if( rxsock->m_rx_req_size > BG96::BG96_BUFF_SIZE) 00768 rxsock->m_rx_req_size= BG96::BG96_BUFF_SIZE; 00769 00770 rxsock->m_rx_callback = sock->_callback; 00771 rxsock->m_rx_cb_data = sock->_data; 00772 // fall through 00773 if( rx_event(rxsock) != EVENT_COMPLETE ){ 00774 rxsock->m_rx_state = READ_ACTIVE; 00775 _eq_schedule(); 00776 debugOutput(DBGMSG_DRV,"EXIT socket_recv, scheduled read of socket %d.", sock->id); 00777 txrx_mutex.unlock(); 00778 return NSAPI_ERROR_WOULD_BLOCK; 00779 } 00780 00781 //got data, fall thru and finish. no need to schedule the background task 00782 if( rxsock->m_rx_state == READ_DOCB ) { 00783 debugOutput(DBGMSG_DRV,"Call socket %d RX call-back",sock->id); 00784 rxsock->m_rx_state = DATA_AVAILABLE; 00785 rxsock->m_rx_callback( rxsock->m_rx_cb_data ); 00786 } 00787 00788 // fall through 00789 00790 case DATA_AVAILABLE: 00791 debugOutput(DBGMSG_DRV,"EXIT socket_recv(),socket %d, return %d bytes",sock->id, rxsock->m_rx_return_cnt); 00792 debugDump_arry((const uint8_t*)data,rxsock->m_rx_return_cnt); 00793 rxsock->m_rx_state = READ_START; 00794 txrx_mutex.unlock(); 00795 return rxsock->m_rx_return_cnt; 00796 00797 case READ_ACTIVE: 00798 case READ_INIT: 00799 debugOutput(DBGMSG_DRV,"EXIT socket_recv(), socket id %d, READ_ACTIVE/INIT", sock->id); 00800 txrx_mutex.unlock(); 00801 return NSAPI_ERROR_WOULD_BLOCK; 00802 00803 case READ_DOCB: 00804 default: 00805 debugOutput(DBGMSG_DRV,"EXIT socket_recv(), NSAPI_ERROR_DEVICE_ERROR"); 00806 txrx_mutex.unlock(); 00807 return NSAPI_ERROR_DEVICE_ERROR; 00808 } 00809 } 00810 00811 /**---------------------------------------------------------- 00812 * @brief check for and retrieve data user requested. Time out 00813 * after TO period unless socket has TO disabled. 00814 * @param pointer to an RXEVENT 00815 * @retval 1 if need to schedule another check, 0 if data received or Timed Out 00816 */ 00817 int BG96Interface::rx_event(RXEVENT *ptr) 00818 { 00819 debugOutput(DBGMSG_EQ,"ENTER rx_event() for socket id %d, size=%d", ptr->m_rx_socketID, ptr->m_rx_req_size); 00820 dbgIO_lock; 00821 int cnt = _BG96.recv(ptr->m_rx_socketID, ptr->m_rx_dptr, ptr->m_rx_req_size); 00822 dbgIO_unlock; 00823 00824 if( cnt == NSAPI_ERROR_DEVICE_ERROR ) { 00825 debugOutput(DBGMSG_EQ,"EXIT rx_event(), error reading socket %d", ptr->m_rx_socketID); 00826 ptr->m_rx_timer=0; 00827 return EVENT_GETMORE; 00828 } 00829 00830 if( cnt>0 ) { //got data, return it to the caller 00831 debugOutput(DBGMSG_EQ,"EXIT rx_event(), socket %d received %d bytes", ptr->m_rx_socketID, cnt); 00832 ptr->m_rx_return_cnt += cnt; 00833 ptr->m_rx_state = DATA_AVAILABLE; 00834 if( ptr->m_rx_callback != NULL ) 00835 ptr->m_rx_state = READ_DOCB; 00836 return EVENT_COMPLETE; 00837 } 00838 00839 if( ++ptr->m_rx_timer > (BG96_READ_TIMEOUTMS/EQ_FREQ) && !ptr->m_rx_disTO ) { //timed out waiting, return 0 to caller 00840 debugOutput(DBGMSG_EQ,"EXIT rx_event(), socket id %d, rx data TIME-OUT!",ptr->m_rx_socketID); 00841 ptr->m_rx_state = DATA_AVAILABLE; 00842 ptr->m_rx_return_cnt = 0; 00843 if( ptr->m_rx_callback != NULL ) 00844 ptr->m_rx_state = READ_DOCB; 00845 return EVENT_COMPLETE; 00846 } 00847 00848 debugOutput(DBGMSG_EQ,"EXIT rx_event(), socket id %d, sechedule for more.", 00849 ptr->m_rx_socketID); 00850 return EVENT_GETMORE; 00851 } 00852 00853 /**---------------------------------------------------------- 00854 * @brief send data, if more data than BG96 can handle at one 00855 * send as much as possible, and schedule another event 00856 * @param pointer to TXEVENT structure 00857 * @retval 1 if need to schedule another event, 0 if data sent 00858 */ 00859 int BG96Interface::tx_event(TXEVENT *ptr) 00860 { 00861 debugOutput(DBGMSG_EQ,"ENTER tx_event(), socket id %d",ptr->m_tx_socketID); 00862 00863 dbgIO_lock; 00864 bool done =_BG96.send(ptr->m_tx_socketID, ptr->m_tx_dptr, ptr->m_tx_req_size); 00865 dbgIO_unlock; 00866 00867 if( done ) 00868 ptr->m_tx_total_sent += ptr->m_tx_req_size; 00869 else{ 00870 debugOutput(DBGMSG_EQ,"EXIT tx_event(), socket id %d, sent no data!",ptr->m_tx_socketID); 00871 return EVENT_GETMORE; 00872 } 00873 00874 if( ptr->m_tx_total_sent < ptr->m_tx_orig_size ) { 00875 ptr->m_tx_dptr += ptr->m_tx_req_size; 00876 ptr->m_tx_req_size = ptr->m_tx_orig_size-ptr->m_tx_total_sent; 00877 00878 if( ptr->m_tx_req_size > BG96::BG96_BUFF_SIZE) 00879 ptr->m_tx_req_size= BG96::BG96_BUFF_SIZE; 00880 00881 debugOutput(DBGMSG_EQ,"EXIT tx_event(), need to send %d more bytes.",ptr->m_tx_req_size); 00882 return EVENT_GETMORE; 00883 } 00884 debugOutput(DBGMSG_EQ,"EXIT tx_event, socket id %d, sent %d bytes",ptr->m_tx_socketID,ptr->m_tx_total_sent); 00885 ptr->m_tx_state = TX_COMPLETE; 00886 if( ptr->m_tx_callback != NULL ) 00887 ptr->m_tx_state = TX_DOCB; 00888 00889 return EVENT_COMPLETE; 00890 } 00891 00892 00893 /**---------------------------------------------------------- 00894 * @brief periodic event(EventQueu thread) to check for RX and TX data. If checking for RX data with TO disabled 00895 * slow down event checking after a while. 00896 * @param none 00897 * @retval none 00898 */ 00899 void BG96Interface::g_eq_event(void) 00900 { 00901 int done = txrx_mutex.trylock(); 00902 bool goSlow = false; 00903 00904 if( scheduled_events > 0 ) 00905 scheduled_events--; 00906 00907 if( !done ) { 00908 _eq_schedule(); 00909 return; 00910 } 00911 00912 done = EVENT_COMPLETE; 00913 for( unsigned int i=0; i<BG96_SOCKET_COUNT; i++ ) { 00914 if( g_socRx[i].m_rx_state == READ_ACTIVE || g_socRx[i].m_rx_disTO) { 00915 done |= rx_event(&g_socRx[i]); 00916 goSlow |= ( g_socRx[i].m_rx_timer > ((BG96_READ_TIMEOUTMS/EQ_FREQ)*(EQ_FREQ_SLOW/EQ_FREQ)) ); 00917 00918 if( goSlow ) 00919 g_socRx[i].m_rx_timer = (BG96_READ_TIMEOUTMS/EQ_FREQ)*(EQ_FREQ_SLOW/EQ_FREQ); 00920 } 00921 00922 if( g_socTx[i].m_tx_state == TX_ACTIVE ) { 00923 goSlow = false; 00924 done |= tx_event(&g_socTx[i]); 00925 } 00926 } 00927 00928 for( unsigned int i=0; i<BG96_SOCKET_COUNT; i++ ) { 00929 if( g_socRx[i].m_rx_state == READ_DOCB ) { 00930 debugOutput(DBGMSG_EQ,"Call socket %d RX call-back",i); 00931 g_socRx[i].m_rx_state = DATA_AVAILABLE; 00932 g_socRx[i].m_rx_callback( g_socRx[i].m_rx_cb_data ); 00933 } 00934 00935 if( g_socTx[i].m_tx_state == TX_DOCB ) { 00936 debugOutput(DBGMSG_EQ,"Call socket %d TX call-back",i); 00937 g_socTx[i].m_tx_state = TX_COMPLETE; 00938 g_socTx[i].m_tx_callback( g_socTx[i].m_tx_cb_data ); 00939 } 00940 } 00941 00942 if( done != EVENT_COMPLETE ) 00943 _eq_schedule(); 00944 00945 debugOutput(DBGMSG_EQ, "EXIT eq_event, queue=%d\n", scheduled_events); 00946 txrx_mutex.unlock(); 00947 } 00948 00949 00950 void BG96Interface::_eq_schedule(void) 00951 { 00952 if( scheduled_events < BG96_SOCKET_COUNT ) { 00953 scheduled_events++; 00954 _bg96_queue.call_in(EQ_FREQ,mbed::Callback<void()>((BG96Interface*)this,&BG96Interface::g_eq_event)); 00955 } 00956 } 00957
Generated on Tue Jul 12 2022 19:02:38 by
1.7.2