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 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
Generated on Sat Jul 16 2022 16:26:31 by
1.7.2