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