Jim Flynn / Mbed OS aws-iot-device-sdk-mbed-c
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BG96Interface.cpp Source File

BG96Interface.cpp

Go to the documentation of this file.
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