Jim Flynn / wnc14a2a-driver
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WNC14A2AInterface.cpp Source File

WNC14A2AInterface.cpp

Go to the documentation of this file.
00001 /**
00002 * copyright (c) 2017-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   WNC14A2AInterface.cpp
00024 *   @brief  WNC14A2A implementation of NetworkInterfaceAPI for Mbed OS
00025 *
00026 *   @author James Flynn
00027 *
00028 *   @date   1-Feb-2018
00029 */
00030 
00031 #include "WNC14A2AInterface.h"
00032 #include <Thread.h>
00033 #include "mbed_events.h"
00034 
00035 #include <string> 
00036 #include <ctype.h>
00037 
00038 #define WNC14A2A_READ_TIMEOUTMS        2000              //read this long total until we decide there is no data to receive in MS
00039 #define WNC14A2A_COMMUNICATION_TIMEOUT 100               //how long (ms) to wait for a WNC14A2A connect response
00040 #define WNC_BUFF_SIZE                  1500              //total number of bytes in a single WNC call
00041 #define UART_BUFF_SIZE                 4000              //size of our internal uart buffer
00042 #define ISR_FREQ                       250               //frequency in ms to run the isr handler
00043 
00044 //
00045 // The WNC device does not generate interrutps on received data, so the module must be polled 
00046 // for data availablility.  To implement a non-blocking mode, interrupts are simulated using
00047 // mbed OS Event Queues.  These Constants are used to manage that sequence.
00048 //
00049 #define READ_INIT                      10
00050 #define READ_START                     11
00051 #define READ_ACTIVE                    12
00052 #define DATA_AVAILABLE                 13
00053 #define TX_IDLE                        20
00054 #define TX_STARTING                    21
00055 #define TX_ACTIVE                      22
00056 #define TX_COMPLETE                    23
00057 
00058 #if MBED_CONF_APP_WNC_DEBUG == true
00059 #define debugOutput(...)      WNC14A2AInterface::_dbOut(__VA_ARGS__)
00060 #define debugDump_arry(...)   WNC14A2AInterface::_dbDump_arry(__VA_ARGS__)
00061 #else
00062 #define debugOutput(...)      {/* __VA_ARGS__ */}
00063 #define debugDump_arry(...)   {/* __VA_ARGS__ */}
00064 #endif
00065 
00066 
00067 //
00068 // GPIO Pins used to initialize the WNC parts on the Avnet WNC Shield
00069 //
00070 DigitalOut  mdm_uart2_rx_boot_mode_sel(PTC17);  // on powerup, 0 = boot mode, 1 = normal boot
00071 DigitalOut  mdm_power_on(PTB9);                 // 0 = modem on, 1 = modem off (hold high for >5 seconds to cycle modem)
00072 DigitalOut  mdm_wakeup_in(PTC2);                // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield
00073 DigitalOut  mdm_reset(PTC12);                   // active high
00074 DigitalOut  shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active
00075 DigitalOut  mdm_uart1_cts(PTD0);                // WNC doesn't utilize RTS/CTS but the pin is connected
00076 
00077 using namespace WncControllerK64F_fk;            // namespace for the AT controller class use
00078 
00079 //! associations for the controller class to use. Order of pins is critical.
00080 WncGpioPinListK64F wncPinList = { 
00081     &mdm_uart2_rx_boot_mode_sel,
00082     &mdm_power_on,
00083     &mdm_wakeup_in,
00084     &mdm_reset,
00085     &shield_3v3_1v8_sig_trans_ena,
00086     &mdm_uart1_cts
00087 };
00088 
00089 Thread smsThread, isrThread;                          //SMS thread for receiving SMS, recv is for simulated rx-interrupt
00090 static Mutex _pwnc_mutex;                           //because WNC class is not re-entrant
00091 
00092 static WNCSOCKET _sockets[WNC14A2A_SOCKET_COUNT];     //WNC supports 8 open sockets but driver only supports 1 currently
00093 BufferedSerial   mdmUart(PTD3,PTD2,UART_BUFF_SIZE,1); //UART for WNC Module
00094 
00095 /*   Constructor
00096 *
00097 *  @brief    May be invoked with or without the debug pointer.
00098 *  @note     After the constructor has completed, call check 
00099 *  _errors to determine if any errors occured. Possible values:
00100 *           NSAPI_ERROR_UNSUPPORTED 
00101 *           NSAPI_ERROR_DEVICE_ERROR
00102 */
00103 WNC14A2AInterface::WNC14A2AInterface(WNCDebug *dbg) : 
00104  m_wncpoweredup(0),
00105  _pwnc(NULL),
00106  m_active_socket(-1),
00107  m_smsmoning(0)
00108 {
00109     _errors = NSAPI_ERROR_OK;  //tracks internal driver errors only
00110     m_debug=0;                 //for internal driver debug
00111 
00112     if( _pwnc ) {              //only a single instance allowed
00113         _errors =  NSAPI_ERROR_UNSUPPORTED;
00114         return;
00115         }
00116     memset(_mac_address,0x00,sizeof(_mac_address));
00117     for( int i=0; i<WNC14A2A_SOCKET_COUNT; i++ ) {
00118         _sockets[i].socket = i;
00119         _sockets[i].addr = NULL;
00120         _sockets[i].opened=false;
00121         _sockets[i]._wnc_opened=false;
00122         _sockets[i].proto=NSAPI_TCP;
00123         }
00124 
00125     _debugUart = dbg;           
00126     if( dbg != NULL ) 
00127         _pwnc = new WncControllerK64F(&wncPinList, &mdmUart, dbg);
00128     else 
00129         _pwnc = new WncControllerK64F_fk::WncControllerK64F(&wncPinList, &mdmUart, NULL);
00130         
00131     if( !_pwnc ) {
00132         debugOutput("FAILED to open WncControllerK64!");
00133         _errors = NSAPI_ERROR_DEVICE_ERROR;
00134         }
00135 
00136     isrThread.start(callback(&isr_queue,&EventQueue::dispatch_forever));
00137 }
00138 
00139 //! Standard destructor
00140 WNC14A2AInterface::~WNC14A2AInterface()
00141 {
00142     delete _pwnc;  //free the existing WncControllerK64F object
00143 }
00144 
00145 
00146 nsapi_error_t WNC14A2AInterface::connect()   //can be called with no arguments or with arguments
00147 {
00148     debugOutput("ENTER connect(void)");
00149     return connect(NULL,NULL,NULL);
00150 }
00151 
00152 nsapi_error_t WNC14A2AInterface::connect(const char *apn, const char *username, const char *password) 
00153 {
00154     debugOutput("ENTER connect(apn,user,pass)");
00155     if( !_pwnc )
00156         return (_errors=NSAPI_ERROR_NO_CONNECTION);
00157 
00158     if (!apn)
00159         apn = "m2m.com.attz";
00160 
00161     _pwnc_mutex.lock();
00162     if (!m_wncpoweredup) {
00163         debugOutput("call powerWncOn(%s,40)",apn);
00164         m_wncpoweredup=_pwnc->powerWncOn(apn,40);
00165         _errors = m_wncpoweredup? 1:0;
00166         }
00167     else {          //powerWncOn already called, set a new APN
00168         debugOutput("set APN=%s",apn);
00169         _errors = _pwnc->setApnName(apn)? 1:0;
00170         }
00171 
00172     _errors |= _pwnc->getWncNetworkingStats(&myNetStats)? 2:0;
00173     _pwnc_mutex.unlock();
00174 
00175     debugOutput("EXIT connect (%02X)",_errors);
00176     return (!_errors)? NSAPI_ERROR_NO_CONNECTION : NSAPI_ERROR_OK;
00177 }
00178 
00179 const char *WNC14A2AInterface::get_ip_address()
00180 {
00181     const char *ptr=NULL; 
00182 
00183     _pwnc_mutex.lock();
00184     if ( _pwnc->getWncNetworkingStats(&myNetStats) ) {
00185         _pwnc_mutex.unlock();
00186         CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
00187         ptr = &myNetStats.ip[0];
00188     }
00189     _pwnc_mutex.unlock();
00190     _errors=NSAPI_ERROR_NO_CONNECTION;
00191     return ptr;
00192 }
00193 
00194 int WNC14A2AInterface::socket_open(void **handle, nsapi_protocol_t proto) 
00195 {
00196     int i;
00197     debugOutput("ENTER socket_open()");
00198 
00199     // search through the available sockets (WNC can only support a max amount).
00200     for( i=0; i<WNC14A2A_SOCKET_COUNT; i++ )
00201         if( !_sockets[i].opened )
00202             break;
00203 
00204     if( i == WNC14A2A_SOCKET_COUNT ) {
00205         _errors=NSAPI_ERROR_NO_SOCKET;
00206         return -1;
00207         }
00208 
00209     m_active_socket = i;               //this is the active socket
00210     _sockets[i].socket = i;            //also save for later
00211     _sockets[i].url="";
00212     _sockets[i].opened = true;         
00213     _sockets[i]._wnc_opened=false;
00214     _sockets[i].addr = NULL;           //not yet open
00215     _sockets[i].proto = proto;         //don't know if it is TCP/UDP
00216     _sockets[i]._callback = NULL;
00217     _sockets[i]._cb_data = NULL;         
00218     *handle = &_sockets[i];
00219 
00220     m_recv_wnc_state = READ_START;
00221     m_tx_wnc_state = TX_IDLE;
00222 
00223     debugOutput("EXIT socket_open; Socket=%d, OPEN=%s, protocol =%s",
00224                 i, _sockets[i].opened?"YES":"NO", (_sockets[i].proto==NSAPI_UDP)?"UDP":"TCP");
00225     
00226     _errors = NSAPI_ERROR_OK;
00227     return i;
00228 }
00229 
00230 int WNC14A2AInterface::socket_connect(void *handle, const SocketAddress &address) 
00231 {
00232     WNCSOCKET *wnc = (WNCSOCKET *)handle;   
00233     int rval = 0;
00234 
00235     debugOutput("ENTER socket_connect(); IP=%s; PORT=%d;", address.get_ip_address(), address.get_port());
00236     
00237     if (!_pwnc || m_active_socket == -1 || !wnc->opened ) {
00238         _errors = NSAPI_ERROR_NO_SOCKET;
00239         return -1;
00240         }
00241 
00242     m_active_socket = wnc->socket;  //in case the user is asking for a different socket
00243     wnc->addr = address;
00244                                 
00245     //
00246     //try connecting to URL if possible, if no url, try IP address
00247     //
00248 
00249     _pwnc_mutex.lock();
00250     if( wnc->url.empty() ) {
00251         if( !_pwnc->openSocketIpAddr(m_active_socket, address.get_ip_address(), address.get_port(), 
00252                                        (wnc->proto==NSAPI_UDP)?0:1, WNC14A2A_COMMUNICATION_TIMEOUT) ) 
00253             rval = -1;
00254         }
00255      else {
00256         if( !_pwnc->openSocketUrl(m_active_socket, wnc->url.c_str(), wnc->addr.get_port(), (wnc->proto==NSAPI_UDP)?0:1) ) 
00257             rval = -1;
00258         }
00259     _pwnc_mutex.unlock();
00260     if( !rval ) {
00261         wnc->_wnc_opened = true;
00262         debugOutput("EXIT socket_connect()");
00263         }
00264 
00265     m_recv_wnc_state = READ_START;
00266     m_tx_wnc_state = TX_IDLE;
00267 
00268     if( wnc->_callback != NULL ) 
00269         wnc->_callback( wnc->_cb_data );
00270 
00271     return rval;
00272 }
00273 
00274 nsapi_error_t WNC14A2AInterface::gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version)
00275 {
00276     nsapi_error_t ret = NSAPI_ERROR_OK;
00277     char ipAddrStr[25];
00278     int  t_socket = 0;  //use a temporary socket place holder
00279 
00280     debugOutput("ENTER gethostbyname(); IP=%s; PORT=%d; URL=%s;", address->get_ip_address(), address->get_port(), name);
00281     memset(ipAddrStr,0x00,sizeof(ipAddrStr));
00282     
00283     if (!_pwnc) 
00284         return (_errors = NSAPI_ERROR_NO_SOCKET);
00285         
00286     if (m_active_socket != -1)      //we might have been called before a socket was opened
00287         t_socket = m_active_socket; //if so, do nothing with the active socket index
00288 
00289     //Execute DNS query.  
00290     _pwnc_mutex.lock();
00291     if( !_pwnc->resolveUrl(t_socket, name) )  
00292         ret = _errors = NSAPI_ERROR_DEVICE_ERROR;
00293 
00294     //Get IP address that the URL was resolved to
00295     if( !_pwnc->getIpAddr(t_socket, ipAddrStr) )
00296         ret = _errors = NSAPI_ERROR_DEVICE_ERROR;
00297     _pwnc_mutex.unlock();
00298 
00299     if( ret != NSAPI_ERROR_OK )
00300         return ret;
00301 
00302     address->set_ip_address(ipAddrStr);
00303 
00304     if( t_socket == m_active_socket ) {
00305         _sockets[m_active_socket].url=name;
00306         _sockets[m_active_socket].addr.set_ip_address(ipAddrStr);
00307         }
00308 
00309     debugOutput("EXIT gethostbyname()");
00310     return (_errors = ret);
00311 }
00312  
00313 
00314 int WNC14A2AInterface::socket_close(void *handle)
00315 {
00316     WNCSOCKET *wnc = (WNCSOCKET*)handle;
00317     int rval = 0;
00318 
00319     debugOutput("ENTER socket_close()");
00320 
00321     if (!_pwnc || m_active_socket == -1) {
00322         _errors = NSAPI_ERROR_NO_SOCKET;
00323         return -1;
00324         }
00325     else
00326         m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
00327     
00328     m_tx_wnc_state = TX_IDLE;               //reset TX state
00329     if( m_recv_wnc_state != READ_START ) {  //reset RX state
00330         m_recv_events = 0;  //force a timeout
00331         while( m_recv_wnc_state !=  DATA_AVAILABLE ) 
00332             wait(1);  //someone called close while a read was happening
00333         }
00334 
00335     _pwnc_mutex.lock();
00336     if( !_pwnc->closeSocket(m_active_socket) ) {
00337         _errors = NSAPI_ERROR_DEVICE_ERROR;
00338         rval = -1;
00339         }
00340     _pwnc_mutex.unlock();
00341 
00342     if( !rval ) {
00343         wnc->opened   = false;       //no longer in use
00344         wnc->addr     = NULL;        //not open
00345         wnc->proto    = NSAPI_TCP;   //assume TCP for now
00346         _errors       = NSAPI_ERROR_OK;
00347         wnc->_cb_data = NULL;
00348         wnc->_callback= NULL;
00349         }
00350 
00351     debugOutput("EXIT socket_close()");
00352     return rval;
00353 }
00354 
00355 const char *WNC14A2AInterface::get_mac_address()
00356 {
00357     string mac, str;
00358     debugOutput("ENTER get_mac_address()");
00359 
00360     _pwnc_mutex.lock();
00361     if( _pwnc->getICCID(&str) ) {
00362         _pwnc_mutex.unlock();
00363         CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), null);
00364         mac = str.substr(3,20);
00365         mac[2]=mac[5]=mac[8]=mac[11]=mac[14]=':';
00366         strncpy(_mac_address, mac.c_str(), mac.length());
00367         debugOutput("EXIT get_mac_address() - %s",_mac_address);
00368         return _mac_address;
00369     }
00370     _pwnc_mutex.unlock();
00371     debugOutput("EXIT get_mac_address() - NULL");
00372     return NULL;
00373 }
00374 
00375 NetworkStack *WNC14A2AInterface::get_stack() {
00376     debugOutput("ENTER/EXIT get_stack()");
00377     return this;
00378 }
00379 
00380 nsapi_error_t WNC14A2AInterface::disconnect() 
00381 {
00382     debugOutput("ENTER/EXIT disconnect()");
00383     return NSAPI_ERROR_OK;
00384 }
00385 
00386 nsapi_error_t WNC14A2AInterface::set_credentials(const char *apn, const char *username, const char *password) 
00387 {
00388 
00389     _errors=NSAPI_ERROR_OK;
00390     debugOutput("ENTER set_credentials()");
00391     if( !_pwnc ) 
00392         return (_errors=NSAPI_ERROR_NO_CONNECTION);
00393         
00394     if( !apn )
00395         return (_errors=NSAPI_ERROR_PARAMETER);
00396 
00397     _pwnc_mutex.lock();
00398     if( !_pwnc->setApnName(apn) )
00399         _errors=NSAPI_ERROR_DEVICE_ERROR;
00400     _pwnc_mutex.unlock();
00401     debugOutput("EXIT set_credentials()");
00402     return _errors;
00403 }
00404 
00405 bool WNC14A2AInterface::registered()
00406 {
00407     debugOutput("ENTER registered()");
00408     _errors=NSAPI_ERROR_OK;
00409 
00410     if( !_pwnc ) {
00411         _errors=NSAPI_ERROR_NO_CONNECTION;
00412         return false;
00413         }
00414 
00415     _pwnc_mutex.lock();
00416     if ( _pwnc->getWncStatus() != WNC_GOOD )
00417         _errors=NSAPI_ERROR_NO_CONNECTION;
00418     _pwnc_mutex.unlock();
00419 
00420     debugOutput("EXIT registered()");
00421     return (_errors==NSAPI_ERROR_OK);
00422 }
00423 
00424 char* WNC14A2AInterface::getSMSnbr( void ) 
00425 {
00426     char * ret=NULL;
00427     string iccid_str;
00428     static string msisdn_str;
00429 
00430     if( !_pwnc ) {
00431         _errors=NSAPI_ERROR_NO_CONNECTION;
00432         return NULL;
00433         }
00434 
00435     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
00436 
00437     _pwnc_mutex.lock();
00438     if( !_pwnc->getICCID(&iccid_str) ) {
00439         _pwnc_mutex.unlock();
00440         return ret;
00441         }
00442     _pwnc_mutex.unlock();
00443  
00444     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
00445 
00446     _pwnc_mutex.lock();
00447     if( _pwnc->convertICCIDtoMSISDN(iccid_str, &msisdn_str) )
00448          ret = (char*)msisdn_str.c_str();    
00449     _pwnc_mutex.unlock();
00450     return ret;
00451 }
00452 
00453 void WNC14A2AInterface::sms_attach(void (*callback)(IOTSMS *))
00454 {
00455     debugOutput("ENTER/EXIT sms_attach()");
00456     _sms_cb = callback;
00457 }
00458 
00459 void WNC14A2AInterface::sms_start(void)
00460 {
00461     _pwnc_mutex.lock();                     
00462     _pwnc->deleteSMSTextFromMem('*');       
00463     _pwnc_mutex.unlock();
00464 }
00465 
00466 void WNC14A2AInterface::sms_listen(uint16_t pp)
00467 {
00468     debugOutput("ENTER sms_listen(%d)",pp);
00469     if( !_pwnc ) {
00470         _errors=NSAPI_ERROR_NO_CONNECTION;
00471         return;
00472         }
00473 
00474     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), fail);
00475 
00476     if( m_smsmoning )
00477         m_smsmoning = false;
00478     if( pp < 1)
00479         pp = 30;
00480 
00481 
00482     debugOutput("setup sms_listen event queue");
00483     smsThread.start(callback(&sms_queue,&EventQueue::dispatch_forever));
00484 
00485     sms_start();
00486     sms_queue.call_every(pp*1000, mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::handle_sms_event));
00487 
00488     m_smsmoning = true;
00489     debugOutput("EXIT sms_listen()");
00490 }
00491 
00492 void WNC14A2AInterface::handle_sms_event()
00493 {
00494     int msgs_available;
00495     debugOutput("ENTER handle_sms_event()");
00496 
00497     if ( _sms_cb && m_smsmoning ) {
00498         CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), fail);
00499         _pwnc_mutex.lock();
00500         msgs_available = _pwnc->readUnreadSMSText(&m_smsmsgs, true);
00501         _pwnc_mutex.unlock();
00502         if( msgs_available ) {
00503             debugOutput("Have %d unread texts present",m_smsmsgs.msgCount);
00504             for( int i=0; i< m_smsmsgs.msgCount; i++ ) {
00505                 m_MsgText.number = m_smsmsgs.e[i].number;
00506                 m_MsgText.date = m_smsmsgs.e[i].date;
00507                 m_MsgText.time = m_smsmsgs.e[i].time;
00508                 m_MsgText.msg = m_smsmsgs.e[i].msg;
00509                 _sms_cb(&m_MsgText);
00510                 }
00511             }
00512         }
00513     debugOutput("EXIT handle_sms_event");
00514 }
00515 
00516 
00517 int WNC14A2AInterface::getSMS(IOTSMS **pmsg) 
00518 {
00519     int msgs_available;
00520 
00521     debugOutput("ENTER getSMS()");
00522     CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), fail);
00523 
00524     _pwnc_mutex.lock();
00525     msgs_available = _pwnc->readUnreadSMSText(&m_smsmsgs, true);
00526     _pwnc_mutex.unlock();
00527 
00528     if( msgs_available ) {
00529         debugOutput("Have %d unread texts present",m_smsmsgs.msgCount);
00530         for( int i=0; i< m_smsmsgs.msgCount; i++ ) {
00531             m_MsgText_array[i].number = m_smsmsgs.e[i].number;
00532             m_MsgText_array[i].date   = m_smsmsgs.e[i].date;
00533             m_MsgText_array[i].time   = m_smsmsgs.e[i].time;
00534             m_MsgText_array[i].msg    = m_smsmsgs.e[i].msg;
00535             pmsg[i] = (IOTSMS*)&m_MsgText_array[i];
00536             }
00537         msgs_available = m_smsmsgs.msgCount;
00538         }
00539     debugOutput("EXIT getSMS");
00540     return msgs_available;
00541 }
00542 
00543 
00544 int WNC14A2AInterface::sendIOTSms(const string& number, const string& message) 
00545 {
00546 
00547     debugOutput("ENTER sendIOTSms(%s,%s)",number.c_str(), message.c_str());
00548     _pwnc_mutex.lock();
00549     int i =  _pwnc->sendSMSText((char*)number.c_str(), message.c_str());
00550     _pwnc_mutex.unlock();
00551 
00552     debugOutput("EXIT sendIOTSms(%s,%s)",number.c_str(), message.c_str());
00553     return i;
00554 }
00555 
00556 
00557 void WNC14A2AInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
00558 {
00559     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00560 
00561     debugOutput("ENTER/EXIT socket_attach()");
00562     wnc->_callback = callback;
00563     wnc->_cb_data = data;
00564 }
00565 
00566 int WNC14A2AInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size)
00567 {
00568     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00569     
00570     debugOutput("ENTER socket_sendto()");
00571     
00572     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), fail);
00573    
00574     if (!wnc->_wnc_opened) {
00575        int err = socket_connect(wnc, address);
00576        if (err < 0) 
00577            return err;
00578        }
00579     wnc->addr = address;
00580 
00581     debugOutput("EXIT socket_sendto()");
00582     return socket_send(wnc, data, size);
00583 }
00584 
00585 int WNC14A2AInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size)
00586 {
00587     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00588     debugOutput("ENTER socket_recvfrom()");
00589 
00590     if (!wnc->_wnc_opened) {
00591        debugOutput("need to open a WNC socket first");
00592        int err = socket_connect(wnc, *address);
00593        if (err < 0) 
00594            return err;
00595        }
00596 
00597     int ret = socket_recv(wnc, (char *)buffer, size);
00598     if (ret >= 0 && address) 
00599         *address = wnc->addr;
00600     debugOutput("EXIT socket_recvfrom()");
00601     return ret;
00602 }
00603 
00604 
00605 int inline WNC14A2AInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) 
00606 {
00607     debugOutput("ENTER/EXIT socket_accept()");
00608     _errors = NSAPI_ERROR_UNSUPPORTED;
00609     return -1;
00610 }
00611 
00612 int inline WNC14A2AInterface::socket_bind(void *handle, const SocketAddress &address) 
00613 {
00614     debugOutput("ENTER/EXIT socket_bind()");
00615     _errors = NSAPI_ERROR_UNSUPPORTED;
00616     return -1;
00617 }
00618 
00619 
00620 int inline WNC14A2AInterface::socket_listen(void *handle, int backlog)
00621 {
00622    debugOutput("ENTER/EXIT socket_listen()");
00623     _errors = NSAPI_ERROR_UNSUPPORTED;
00624     return -1;
00625 }
00626 
00627 void WNC14A2AInterface::doDebug( int v )
00628 {
00629     #if MBED_CONF_APP_WNC_DEBUG == true
00630     if( !_pwnc )
00631         _errors = NSAPI_ERROR_DEVICE_ERROR;
00632     else {
00633         _pwnc_mutex.lock();
00634         _pwnc->enableDebug( (v&1), (v&2) );
00635         _pwnc_mutex.unlock();
00636         }
00637 
00638     m_debug= v;
00639 
00640     debugOutput("SET debug flag to 0x%02X",v);
00641     #endif
00642 }
00643 
00644 /** function to dump a user provided array.
00645 *
00646 * @author James Flynn
00647 * @param  data    pointer to the data array to dump
00648 * @param  size    number of bytes to dump
00649 * @return void
00650 * @date 1-Feb-2018
00651 */
00652 void WNC14A2AInterface::_dbDump_arry( const uint8_t* data, unsigned int size )
00653 {
00654     #if MBED_CONF_APP_WNC_DEBUG == true
00655     char buffer[256];
00656     unsigned int i, k;
00657 
00658     if( _debugUart != NULL && (m_debug & 0x08) ) {
00659         for (i=0; i<size; i+=16) {
00660             sprintf(buffer,"[WNC Driver]:0x%04X: ",i);
00661             _debugUart->puts(buffer);
00662             for (k=0; k<16; k++) {
00663                 sprintf(buffer, "%02X ", data[i+k]);
00664                 _debugUart->puts(buffer);
00665                 }
00666             _debugUart->puts(" -- ");
00667             for (k=0; k<16; k++) {
00668                 sprintf(buffer, "%2c", isprint(data[i+k])? data[i+k]:'.');
00669                 _debugUart->puts(buffer);
00670                 }
00671             _debugUart->puts("\n\r");
00672             }
00673         }
00674     #endif
00675 }
00676 
00677 void WNC14A2AInterface::_dbOut(const char *format, ...) 
00678 {
00679     #if MBED_CONF_APP_WNC_DEBUG == true
00680     char buffer[256];
00681 
00682     sprintf(buffer,"[WNC Driver]: ");
00683     if( _debugUart != NULL && (m_debug & 0x0c) ) {
00684         va_list args;
00685         va_start (args, format);
00686         _debugUart->puts(buffer);
00687         vsnprintf(buffer, sizeof(buffer), format, args);
00688         _debugUart->puts(buffer);
00689         _debugUart->putc('\n');
00690         va_end (args);
00691         }
00692     #endif
00693 }
00694 
00695 int WNC14A2AInterface::socket_recv(void *handle, void *data, unsigned size) 
00696 {
00697     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00698 
00699     debugOutput("ENTER socket_recv(), request %d bytes",size);
00700 
00701     if (!_pwnc || m_active_socket == -1) 
00702         return (_errors = NSAPI_ERROR_NO_SOCKET);
00703 
00704     if( size < 1 || data == NULL )  // should never happen
00705         return 0; 
00706 
00707     switch( m_recv_wnc_state ) {
00708         case READ_START:  //need to start a read sequence of events
00709             m_recv_wnc_state = READ_INIT;
00710             m_recv_socket   = wnc->socket; //just in case sending to a socket that wasn't last used
00711             m_recv_dptr     = (uint8_t*)data;
00712             m_recv_orig_size= size;
00713             m_recv_total_cnt= 0;
00714             m_recv_timer    = 0;
00715             m_recv_events   = 1;
00716             m_recv_req_size = (uint32_t)size;
00717             m_recv_return_cnt=0;
00718 
00719             if( m_recv_req_size > WNC_BUFF_SIZE) {
00720                 m_recv_events  =  ((uint32_t)size/WNC_BUFF_SIZE);
00721                 m_recv_req_size= WNC_BUFF_SIZE;
00722                 }
00723             m_recv_callback = wnc->_callback;
00724             m_recv_cb_data  = wnc->_cb_data;
00725 
00726             if( !rx_event() ){
00727                 m_recv_wnc_state = READ_ACTIVE;
00728                 isr_queue.call_in(ISR_FREQ,mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::wnc_isr_event));
00729                 return NSAPI_ERROR_WOULD_BLOCK;
00730                 }
00731             //was able to get the requested data in a single transaction so fall thru and finish
00732             //no need to schedule the background task
00733 
00734         case DATA_AVAILABLE:
00735             debugOutput("EXIT socket_recv(), return %d bytes",m_recv_return_cnt);
00736             debugDump_arry((const uint8_t*)data,m_recv_return_cnt);
00737             m_recv_wnc_state = READ_START;
00738             return m_recv_return_cnt;
00739 
00740         case READ_INIT:
00741         case READ_ACTIVE:
00742             return NSAPI_ERROR_WOULD_BLOCK;
00743 
00744         default:
00745             debugOutput("EXIT socket_recv(), NSAPI_ERROR_DEVICE_ERROR");
00746             return (_errors = NSAPI_ERROR_DEVICE_ERROR);
00747         }
00748 }
00749 
00750 
00751 int WNC14A2AInterface::socket_send(void *handle, const void *data, unsigned size) 
00752 {
00753     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00754 
00755     debugOutput("ENTER socket_send() send %d bytes",size);
00756 
00757     if (!_pwnc || m_active_socket == -1) {
00758         _errors = NSAPI_ERROR_NO_SOCKET;
00759         return 0;
00760         }
00761     else
00762         m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
00763 
00764     if( size < 1 || data == NULL )  // should never happen
00765         return 0; 
00766 
00767     switch( m_tx_wnc_state ) {
00768         case TX_IDLE:
00769             m_tx_wnc_state = TX_STARTING;
00770             debugDump_arry((const uint8_t*)data,size);
00771             m_tx_socket    = wnc->socket; //just in case sending to a socket that wasn't last used
00772             m_tx_dptr      = (uint8_t*)data;
00773             m_tx_orig_size = size;
00774             m_tx_req_size  = (uint32_t)size;
00775             m_tx_total_sent= 0;
00776             m_tx_callback  = wnc->_callback;
00777             m_tx_cb_data   = wnc->_cb_data;
00778 
00779             if( m_tx_req_size > UART_BUFF_SIZE ) 
00780                 m_tx_req_size= UART_BUFF_SIZE;
00781 
00782             if( !tx_event() ) {   //if we didn't sent all the data at once, continue in background
00783                 m_tx_wnc_state = TX_ACTIVE;
00784                 isr_queue.call_in(ISR_FREQ,mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::wnc_isr_event));
00785                 return NSAPI_ERROR_WOULD_BLOCK;
00786                 }
00787             //all data sent so fall through to TX_COMPLETE
00788 
00789         case TX_COMPLETE:
00790             debugOutput("EXIT socket_send(), sent %d bytes", m_tx_total_sent);
00791             m_tx_wnc_state = TX_IDLE;
00792             return m_tx_total_sent;
00793 
00794         case TX_ACTIVE:
00795         case TX_STARTING:
00796             return NSAPI_ERROR_WOULD_BLOCK;
00797 
00798         default:
00799             debugOutput("EXIT socket_send(), NSAPI_ERROR_DEVICE_ERROR");
00800             return (_errors = NSAPI_ERROR_DEVICE_ERROR);
00801         }
00802 }
00803 
00804 
00805 void WNC14A2AInterface::wnc_isr_event()
00806 {
00807     int done = 1;
00808 
00809     debugOutput("ENTER wnc_isr_event()");
00810 
00811     if( m_recv_wnc_state == READ_ACTIVE ) 
00812         done &= rx_event();
00813     if( m_tx_wnc_state == TX_ACTIVE )
00814         done &= tx_event();
00815 
00816     if( !done ) 
00817         isr_queue.call_in(ISR_FREQ,mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::wnc_isr_event));
00818 
00819     debugOutput("EXIT wnc_isr_event()");
00820 }
00821 
00822 
00823 int WNC14A2AInterface::tx_event()
00824 {
00825     debugOutput("ENTER tx_event()");
00826 
00827     _pwnc_mutex.lock();
00828     if( _pwnc->write(m_tx_socket, m_tx_dptr, m_tx_req_size) ) 
00829         m_tx_total_sent += m_tx_req_size;
00830     else
00831         debugOutput("tx_event WNC failed to send()");
00832     CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), resume);
00833     _pwnc_mutex.unlock();
00834     
00835     if( m_tx_total_sent < m_tx_orig_size ) {
00836         m_tx_dptr += m_tx_req_size;
00837         m_tx_req_size = m_tx_orig_size-m_tx_total_sent;
00838 
00839         if( m_tx_req_size > UART_BUFF_SIZE) 
00840             m_tx_req_size= UART_BUFF_SIZE;
00841 
00842         debugOutput("EXIT tx_event(), need to send %d more bytes.",m_tx_req_size);
00843         return 0;
00844         }
00845     debugOutput("EXIT tx_event, data sent");
00846     m_tx_wnc_state = TX_COMPLETE;
00847     if( m_tx_callback != NULL ) 
00848         m_tx_callback( m_tx_cb_data );
00849     m_tx_cb_data = NULL; 
00850     m_tx_callback = NULL;
00851 
00852     return 1;
00853 }
00854 
00855 int WNC14A2AInterface::rx_event()
00856 {
00857     uint32_t k;
00858 
00859     debugOutput("ENTER rx_event()");
00860     _pwnc_mutex.lock();
00861     int cnt = _pwnc->read(m_recv_socket, m_recv_dptr,  m_recv_req_size);
00862     CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), resume);
00863     _pwnc_mutex.unlock();
00864     if( cnt ) {
00865         m_recv_dptr += cnt;
00866         m_recv_total_cnt += cnt;
00867         m_recv_req_size = m_recv_orig_size-m_recv_total_cnt;
00868         if( m_recv_req_size > WNC_BUFF_SIZE )
00869             m_recv_req_size = WNC_BUFF_SIZE;
00870         --m_recv_events;
00871         m_recv_timer = 0;  //restart the timer
00872         }
00873     else if( ++m_recv_timer > (WNC14A2A_READ_TIMEOUTMS/ISR_FREQ) ) {
00874         //didn't get all requested data and we timed out waiting
00875         CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), resume);
00876         debugOutput("EXIT rx_event(), TIME-OUT!");
00877         k = m_recv_return_cnt = m_recv_total_cnt;
00878         m_recv_wnc_state = DATA_AVAILABLE;
00879         if( m_recv_callback != NULL ) 
00880             m_recv_callback( m_recv_cb_data );
00881         m_recv_cb_data = NULL; 
00882         m_recv_callback = NULL;
00883         m_recv_return_cnt = k;
00884         return 1;
00885         }
00886 
00887     if( m_recv_events > 0 ) {
00888         debugOutput("EXIT rx_event() but sechedule for more data.");
00889         return 0;
00890         }
00891     else if( m_recv_total_cnt >= m_recv_orig_size ){
00892         k = m_recv_return_cnt = m_recv_total_cnt;  //save because the callback func may call RX again on us
00893         debugOutput("EXIT rx_event(), data available.");
00894         m_recv_wnc_state = DATA_AVAILABLE;  
00895         if( m_recv_callback != NULL ) 
00896             m_recv_callback( m_recv_cb_data );
00897         m_recv_cb_data = NULL;
00898         m_recv_callback = NULL;
00899         m_recv_return_cnt = k;
00900         return 1;
00901         }
00902     else{
00903         debugOutput("EXIT rx_event() but sechedule for more data.");
00904         return 0;
00905         }
00906      
00907 }
00908