Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

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