Use this interface to connect to and interact with the WNC M14A2A LTE Cellular Data Module which is provided by Wistron NeWeb Corporation (WNC) when using ARMmbed v5. The interface provides a Networking interface that can be used with the AT&T Cellular IoT Starter Kit that is sold by Avnet (http://cloudconnectkits.org/product/att-cellular-iot-starter-kit).

Dependencies:   WncControllerK64F

Dependents:   easy-connect-wnc easy-connect easy-connect111

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WNC14A2AInterface.cpp Source File

WNC14A2AInterface.cpp

00001 
00002 #include "WNC14A2AInterface.h"
00003 #include <Thread.h>
00004 #include <string> 
00005 
00006 /** WNC14A2AInterface class
00007  *  Implementation of the NetworkInterface for the AT&T IoT Starter Kit 
00008  *  based on the WNC 14A2A LTE Data Module
00009  */
00010 
00011 #define WNC14A2A_MISC_TIMEOUT 3000
00012 #define WNC14A2A_RESTART_TIMEOUT 10000
00013 #define WNC14A2A_COMMUNICATION_TIMEOUT 100
00014 #define READ_EVERYMS    500
00015 
00016 /////////////////////////////////////////////////////
00017 // NXP GPIO Pins that are used to initialize the WNC Shield
00018 /////////////////////////////////////////////////////
00019 DigitalOut  mdm_uart2_rx_boot_mode_sel(PTC17);  // on powerup, 0 = boot mode, 1 = normal boot
00020 DigitalOut  mdm_power_on(PTB9);                 // 0 = modem on, 1 = modem off (hold high for >5 seconds to cycle modem)
00021 DigitalOut  mdm_wakeup_in(PTC2);                // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield
00022 DigitalOut  mdm_reset(PTC12);                   // active high
00023 DigitalOut  shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active
00024 DigitalOut  mdm_uart1_cts(PTD0);
00025 
00026 // Define pin associations for the controller class to use be careful to 
00027 //  keep the order of the pins in the initialization list.
00028 
00029 using namespace WncControllerK64F_fk;       // namespace for the controller class use
00030 
00031 WncGpioPinListK64F wncPinList = { 
00032     &mdm_uart2_rx_boot_mode_sel,
00033     &mdm_power_on,
00034     &mdm_wakeup_in,
00035     &mdm_reset,
00036     &shield_3v3_1v8_sig_trans_ena,
00037     &mdm_uart1_cts
00038 };
00039 
00040 Thread smsThread;
00041 static Mutex _pwnc_mutex;
00042 
00043 static WNCSOCKET _sockets[WNC14A2A_SOCKET_COUNT];
00044 BufferedSerial mdmUart(PTD3,PTD2,1024,1);       //UART for WNC Module
00045 
00046 //-------------------------------------------------------------------------
00047 //
00048 // Class constructor.  May be invoked with or without the APN and/or pointer
00049 // to a debug output.  After the constructor has completed, the user can 
00050 // check _errors to determine if any errors occured during instanciation.
00051 // _errors = 0 when no errors occured
00052 //           1 when power-on error occured
00053 //           2 when settng the APN error occured
00054 //           4 when unable to get the network configuration
00055 //           8 when allocating a new WncControllerK64F object failed
00056 //          NSAPI_ERROR_UNSUPPORTED when attempting to create a second object
00057 //
00058 
00059 WNC14A2AInterface::WNC14A2AInterface(WNCDebug *dbg) : 
00060  m_wncpoweredup(0),
00061  _pwnc(NULL),
00062  m_active_socket(-1),
00063  m_smsmoning(0)
00064 {
00065     _errors = NSAPI_ERROR_OK;
00066     
00067     m_debug=false;
00068 
00069     if( _pwnc ) { //can only have a single instance of class
00070         _errors =  NSAPI_ERROR_UNSUPPORTED;
00071         return;
00072         }
00073     for( int i=0; i<WNC14A2A_SOCKET_COUNT; i++ ) {
00074         _sockets[i].socket = i;
00075         _sockets[i].addr = NULL;
00076         _sockets[i].opened=false;
00077         _sockets[i].proto=NSAPI_TCP;
00078         }
00079 
00080     
00081     memset(_mac_address,0x00,sizeof(_mac_address));
00082 
00083     _debugUart = dbg;
00084     if( dbg != NULL ) {
00085         dbg->printf("Adding DEBUG output\n");
00086         _pwnc = new WncControllerK64F(&wncPinList, &mdmUart, dbg);
00087         m_debug=true;
00088         if( _pwnc ) 
00089             _pwnc->enableDebug(1,1);
00090         }
00091     else 
00092         _pwnc = new WncControllerK64F_fk::WncControllerK64F(&wncPinList, &mdmUart, NULL);
00093         
00094     if( !_pwnc ) {
00095         debugOutput(_debugUart,(char*)", FAILED!\n");
00096         _errors = NSAPI_ERROR_DEVICE_ERROR;
00097         }
00098     else
00099         debugOutput(_debugUart, (char*)"\n");
00100 }
00101 
00102 /*-------------------------------------------------------------------------
00103  * standard destructor... free up allocated memory
00104  */
00105 
00106 WNC14A2AInterface::~WNC14A2AInterface()
00107 {
00108     delete _pwnc;  //free the existing WncControllerK64F object
00109 }
00110 
00111 nsapi_error_t WNC14A2AInterface::connect() 
00112 {
00113     debugOutput(_debugUart,(char*)"+CALLED connect(void)\n");
00114     return connect(NULL,NULL,NULL);
00115 }
00116 
00117 /*-------------------------------------------------------------------------
00118  * This call powers up the WNC module and connects to the user specified APN.  If no APN is provided
00119  * a default one of 'm2m.com.attz' will be used (the NA APN)
00120  *
00121  * Input: *apn is the APN string to use
00122  *        *username - NOT CURRENTLY USED
00123  *        *password - NOT CURRENTLY USED
00124  *
00125  * Output: none
00126  *
00127  * Return: nsapi_error_t
00128  */
00129 nsapi_error_t WNC14A2AInterface::connect(const char *apn, const char *username, const char *password) 
00130 {
00131     debugOutput(_debugUart,(char*)"+ENTER connect(apn,user,pass)\n");
00132     if( !_pwnc )
00133         return (_errors=NSAPI_ERROR_NO_CONNECTION);
00134 
00135     if (!apn)
00136         apn = "m2m.com.attz";
00137 
00138     if (!m_wncpoweredup) {
00139         debugOutput(_debugUart,(char*)"+call powerWncOn using '%s'\n",apn);
00140         _pwnc_mutex.lock();
00141         m_wncpoweredup=_pwnc->powerWncOn(apn,40);
00142         _pwnc_mutex.unlock();
00143         _errors = m_wncpoweredup? 1:0;
00144         }
00145     else { //we've already called powerWncOn and set the APN, so just set the APN 
00146         debugOutput(_debugUart,(char*)"+already powered on, set APN to: %s\n",apn);
00147         _pwnc_mutex.lock();
00148         _errors = _pwnc->setApnName(apn)? 1:0;
00149         _pwnc_mutex.unlock();
00150         }
00151 
00152     _pwnc_mutex.lock();
00153     _errors |= _pwnc->getWncNetworkingStats(&myNetStats)? 2:0;
00154     _pwnc_mutex.unlock();
00155 
00156     debugOutput(_debugUart,(char*)"+EXIT connect %02X\n",_errors);
00157     return (!_errors)? NSAPI_ERROR_NO_CONNECTION : NSAPI_ERROR_OK;
00158 }
00159 
00160 /*--------------------------------------------------------------------------
00161  * This function calls the WNC to retrieve the device (this WNC) connected IP 
00162  * address once we are connected to the APN.
00163  *
00164  * Inputs: NONE.
00165  *
00166  * Output: none.
00167  *
00168  * Return: pointer to the IP string or NULL 
00169  */
00170 const char *WNC14A2AInterface::get_ip_address()
00171 {
00172     const char *ptr=NULL; 
00173 
00174     _pwnc_mutex.lock();
00175     if ( _pwnc->getWncNetworkingStats(&myNetStats) ) {
00176         CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
00177         ptr = &myNetStats.ip[0];
00178     }
00179     _pwnc_mutex.unlock();
00180     _errors=NSAPI_ERROR_NO_CONNECTION;
00181     return ptr;
00182 }
00183 
00184 #if 0
00185 /*--------------------------------------------------------------------------
00186  * This function calls the WNC to retrieve the currently connected IP address
00187  * it will be a bogus 192.168.0.1 if we are not connected to anyone
00188  *
00189  * Inputs: NONE.
00190  *
00191  * Output: none.
00192  *
00193  * Return: pointer to the IP string or NULL 
00194  */
00195 const char *WNC14A2AInterface::get_ip_address()
00196 {
00197     static char *ptr=NULL, ipAddrStr[25];
00198     debugOutput(_debugUart,(char*)"+ENTER get_ip_address()\n");
00199 
00200     memset(ipAddrStr, 0x00, sizeof(ipAddrStr));
00201     _pwnc_mutex.lock();
00202 
00203     if( _pwnc && m_active_socket != -1 )
00204         if( _pwnc->getIpAddr(m_active_socket, ipAddrStr) )
00205           ptr=ipAddrStr;
00206     _pwnc_mutex.unlock();
00207     _errors=NSAPI_ERROR_NO_CONNECTION;
00208     return ptr;
00209 }
00210 #endif
00211 
00212 /* -------------------------------------------------------------------------
00213  * Open a socket for the WNC.  This doesn't actually open the socket within
00214  * the WNC, it only allocates a socket device and saves the pertinet info
00215  * that will be required with the WNC socket is opened. The m_active_socket
00216  * is also updated to this socket as it is assumed this socket should be used
00217  * for subsequent interactions.
00218  *
00219  * Input: 
00220  *  - a pointer to a handle pointer.  
00221  *  - The type of socket this will be, either NSAPI_UDP or NSAP_TCP
00222  *
00223  * Output: *handle is updated
00224  *
00225  * Return:
00226  *  - socket being used if successful, -1 on failure
00227  */
00228 int WNC14A2AInterface::socket_open(void **handle, nsapi_protocol_t proto) 
00229 {
00230     int i;
00231     debugOutput(_debugUart,(char*)"+ENTER socket_open()\n");
00232 
00233     // search through the available sockets (WNC can only support a max amount).
00234     for( i=0; i<WNC14A2A_SOCKET_COUNT; i++ )
00235         if( !_sockets[i].opened )
00236             break;
00237 
00238     if( i == WNC14A2A_SOCKET_COUNT ) {
00239         _errors=NSAPI_ERROR_NO_SOCKET;
00240         return -1;
00241         }
00242 
00243     m_active_socket = i;           
00244     _sockets[i].socket = i;        //save this index to make easier later-on
00245     _sockets[i].url="";
00246     _sockets[i].opened = true;     //ok, we are using this socket now
00247     _sockets[i].addr = NULL;       //but we haven't opened it yet
00248     _sockets[i].proto = (proto == NSAPI_UDP) ? 0 : 1; //set it up for what WNC wants
00249     *handle = &_sockets[i];
00250 
00251     debugOutput(_debugUart,(char*)"+USING Socket index %d, OPEN=%s, proto =%d\nEXIT socket_open()\n",
00252     i, _sockets[i].opened?"YES":"NO", _sockets[i].proto);
00253     
00254     _errors = NSAPI_ERROR_OK;
00255     return i;
00256 }
00257 
00258 /*-------------------------------------------------------------------------
00259  * Connect a socket to a IP/PORT.  Before you can connect a socket, you must have opened
00260  * it.
00261  *
00262  * Input: handle - pointer to the socket to use
00263  *        address- the IP/Port pair that will be used
00264  *
00265  * Output: none
00266  *
00267  * return: 0 or greater on success (value is the socket ID)
00268  *        -1 on failure
00269  */
00270 int WNC14A2AInterface::socket_connect(void *handle, const SocketAddress &address) 
00271 {
00272     WNCSOCKET *wnc = (WNCSOCKET *)handle;   
00273 
00274     debugOutput(_debugUart,(char*)"+ENTER socket_connect()\n");
00275     debugOutput(_debugUart,(char*)"+IP  = %s\n+PORT= %d\n", address.get_ip_address(), address.get_port());
00276     
00277     if (!_pwnc || m_active_socket == -1) {
00278         _errors = NSAPI_ERROR_NO_SOCKET;
00279         return -1;
00280         }
00281 
00282     if( !wnc->opened ) {
00283         _errors = NSAPI_ERROR_NO_SOCKET;
00284         return -1;
00285         }
00286     m_active_socket = wnc->socket;  //in case the user is asking for a different socket
00287     wnc->addr = address;
00288                                 
00289     //we will always connect using the URL if possible, if no url has been provided, try the IP address
00290     if( wnc->url.empty() ) {
00291         debugOutput(_debugUart,(char*)"+call openSocketIpAddr(%d,%s,%d,%d)\n",m_active_socket, 
00292                            address.get_ip_address(), address.get_port(), wnc->proto);
00293         if( !_pwnc->openSocketIpAddr(m_active_socket, address.get_ip_address(), address.get_port(), 
00294                                  wnc->proto, WNC14A2A_COMMUNICATION_TIMEOUT) ) {
00295             _errors = NSAPI_ERROR_NO_SOCKET;
00296             return -1;
00297             }
00298         }
00299      else {
00300         debugOutput(_debugUart,(char*)"+call openSocketUrl(%d,%s,%d,%d)\n", m_active_socket, 
00301                            wnc->url.c_str(), wnc->addr.get_port(), wnc->proto);
00302         if( !_pwnc->openSocketUrl(m_active_socket, wnc->url.c_str(), wnc->addr.get_port(), wnc->proto) ) {
00303             _errors = NSAPI_ERROR_NO_SOCKET;
00304             return -1;
00305             }
00306         }
00307 
00308     debugOutput(_debugUart,(char*)"+SOCKET %d CONNECTED!\n+URL=%s\n+IP=%s; PORT=%d\n+EXIT socket_connect()\n\n",m_active_socket,
00309                 wnc->url.c_str(), wnc->addr.get_ip_address(), wnc->addr.get_port());
00310     return 0;
00311 }
00312 
00313 /*-------------------------------------------------------------------------
00314  * Perform a URL name resolve, update the IP/Port pair, and nsapi_version. nsapi_version
00315  * could be either NSAPI_IPv4 or NSAPI_IPv6 but this functional is hard coded ti NSAPI_IPv4
00316  * for now. The currently active socket is used for the resolution.  
00317  *
00318  * Input: name - the URL to resolve
00319  *
00320  * Output: address - the IP/PORT pair this URL resolves to
00321  *         version - always assumed to be NSAPI_IPv4  currently
00322  *
00323  * Return: nsapi_error_t
00324  */
00325 
00326 nsapi_error_t WNC14A2AInterface::gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version)
00327 {
00328     nsapi_error_t ret = NSAPI_ERROR_OK;
00329     char ipAddrStr[25];
00330     int  t_socket = 0;  //use a temporary socket place holder
00331 
00332     debugOutput(_debugUart,(char*)"+ENTER gethostbyname()()\n+CURRENTLY:\n");
00333     debugOutput(_debugUart,(char*)"+URL = %s\n+IP  = %s\n+PORT= %d\n", name, address->get_ip_address(), address->get_port());
00334     memset(ipAddrStr,0x00,sizeof(ipAddrStr));
00335     
00336     if (!_pwnc) 
00337         return (_errors = NSAPI_ERROR_NO_SOCKET);
00338         
00339     if (m_active_socket != -1)      //we might have been called before a socket was opened
00340         t_socket = m_active_socket; //if so, do nothing with the active socket index
00341 
00342     //Execute DNS query.  
00343     if( !_pwnc->resolveUrl(t_socket, name) )  
00344         return (_errors = NSAPI_ERROR_DEVICE_ERROR);
00345 
00346     //Now, get the IP address that the URL was resolved to
00347     if( !_pwnc->getIpAddr(t_socket, ipAddrStr) )
00348         return (_errors = NSAPI_ERROR_DEVICE_ERROR);
00349 
00350     address->set_ip_address(ipAddrStr);
00351     debugOutput(_debugUart,(char*)"+resolveUrl returned IP=%s\n",ipAddrStr);
00352     if( t_socket == m_active_socket ) {
00353         _sockets[m_active_socket].url=name;
00354         _sockets[m_active_socket].addr.set_ip_address(ipAddrStr);
00355         }
00356 
00357     debugOutput(_debugUart,(char*)"+EXIT gethostbyname()\n+URL = %s\n+IP  = %s\n+PORT= %d\n\n", 
00358                 _sockets[m_active_socket].url.c_str(), address->get_ip_address(), 
00359                 address->get_port());
00360     _errors = ret;
00361     return ret;
00362 }
00363  
00364 /*-------------------------------------------------------------------------
00365  * using the specified socket, send the data.
00366  *
00367  * Input: handle of the socket to use
00368  *        pointer to the data to send
00369  *        amount of data being sent
00370  *
00371  * Output: none
00372  *
00373  * Return: number of bytes that was sent
00374  */
00375 int WNC14A2AInterface::socket_send(void *handle, const void *data, unsigned size) 
00376 {
00377     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00378     int r = -1;
00379     debugOutput(_debugUart,(char*)"+ENTER socket_send()\n");
00380 
00381     if (!_pwnc || m_active_socket == -1) {
00382         _errors = NSAPI_ERROR_NO_SOCKET;
00383         return 0;
00384         }
00385     else
00386         m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
00387 
00388     debugOutput(_debugUart,(char*)"+SOCKET %d is %s, URL=%s, IP=%s, PORT=%d\n",m_active_socket,
00389         (char*)wnc->opened?"OPEN":"CLOSED",wnc->url.c_str(),wnc->addr.get_ip_address(),wnc->addr.get_port());
00390     debugOutput(_debugUart,(char*)"+WRITE [%s] (%d bytes) to socket #%d\n",data,size,wnc->socket);
00391 
00392     _pwnc_mutex.lock();
00393     if( _pwnc->write(m_active_socket, (const uint8_t*)data, size) ) 
00394        r = size;
00395     else
00396        debugOutput(_debugUart,(char*)"+ERROR: write to socket %d failed!\n",m_active_socket);
00397     _pwnc_mutex.unlock();
00398 
00399     debugOutput(_debugUart,(char*)"+EXIT socket_send(), successful: %d\n\n",r);
00400     return r;
00401 }  
00402 
00403 /*-------------------------------------------------------------------------
00404  * Called to receive data.  
00405  *
00406  * Input: handle to the socket we want to read from
00407  *
00408  * Output: data we receive is placed into the data buffer
00409  *         size is the size of the buffer
00410  *
00411  * Returns: The number of bytes received or -1 if an error occured
00412  */
00413 int WNC14A2AInterface::socket_recv(void *handle, void *data, unsigned size) 
00414 {
00415     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00416     size_t done, cnt;
00417     Timer t;
00418 
00419     debugOutput(_debugUart,(char*)"+ENTER socket_recv(); read up to %d bytes\n",size);
00420 
00421     memset(data,0x00,size);  
00422     if (!_pwnc || m_active_socket == -1) {
00423         _errors = NSAPI_ERROR_NO_SOCKET;
00424         return -1;
00425         }
00426     else
00427         m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
00428 
00429     t.start();
00430     do {
00431         if( !(t.read_ms() % READ_EVERYMS) )
00432           cnt = done = _pwnc->read(m_active_socket, (uint8_t *)data, (uint32_t) size);
00433         done = (cnt || (t.read_ms() > WNC14A2A_MISC_TIMEOUT))? 1:0;
00434         }
00435     while( !done );
00436     t.stop();
00437     
00438     if( _pwnc->getWncStatus() != WNC_GOOD ) {
00439         _errors = NSAPI_ERROR_DEVICE_ERROR;
00440         return -1;
00441         }
00442 
00443     debugOutput(_debugUart,(char*)"+EXIT socket_recv(), ret=%d\n",cnt);
00444     return cnt;
00445 }
00446 
00447 /*-------------------------------------------------------------------------
00448  * Close a socket 
00449  *
00450  * Input: the handle to the socket to close
00451  *
00452  * Output: none
00453  *
00454  * Return: -1 on error, otherwise 0
00455  */
00456 int WNC14A2AInterface::socket_close(void *handle)
00457 {
00458     WNCSOCKET *wnc = (WNCSOCKET*)handle;
00459     debugOutput(_debugUart,(char*)"+CALLED socket_close()\n");
00460 
00461     if (!_pwnc || m_active_socket == -1) {
00462         _errors = NSAPI_ERROR_NO_SOCKET;
00463         return -1;
00464         }
00465     else
00466         m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
00467     
00468     if( !_pwnc->closeSocket(m_active_socket) ) {
00469         _errors = NSAPI_ERROR_DEVICE_ERROR;
00470         return -1;
00471         }
00472 
00473     wnc->opened = false;     //no longer in use
00474     wnc->addr = NULL;        //not open
00475     wnc->proto = 0;  //assume TCP for now
00476     _errors = NSAPI_ERROR_OK;
00477     return 0;
00478 }
00479 
00480 /*-------------------------------------------------------------------------
00481  * return the MAC for this device.  Because there is no MAC Ethernet 
00482  * address to return, this function returns a bogus MAC address created 
00483  * from the ICCD on the SIM that is being used.
00484  *
00485  * Input: none
00486  *
00487  * Output: none
00488  *
00489  * Return: MAC string containing "NN:NN:NN:NN:NN:NN" or NULL
00490  */
00491 const char *WNC14A2AInterface::get_mac_address()
00492 {
00493     string mac, str;
00494     debugOutput(_debugUart,(char*)"+ENTER get_mac_address()\n");
00495 
00496     if( _pwnc->getICCID(&str) ) {
00497         CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), null);
00498         mac = str.substr(3,20);
00499         mac[2]=mac[5]=mac[8]=mac[11]=mac[14]=':';
00500         strncpy(_mac_address, mac.c_str(), mac.length());
00501         return _mac_address;
00502     }
00503     return NULL;
00504 }
00505 
00506 /*-------------------------------------------------------------------------
00507  * return a pointer to the current WNC14A2AInterface
00508  */
00509 NetworkStack *WNC14A2AInterface::get_stack() {
00510     debugOutput(_debugUart,(char*)"+CALLED get_stack()\n");
00511     return this;
00512 }
00513 
00514 /*-------------------------------------------------------------------------
00515  * Disconnnect from the 14A2A, but we can not do that
00516  * so just return saying everything is ok.
00517  */
00518 nsapi_error_t WNC14A2AInterface::disconnect() 
00519 {
00520     debugOutput(_debugUart,(char*)"+CALLED disconnect()\n");
00521     return NSAPI_ERROR_OK;
00522 }
00523 
00524 /*-------------------------------------------------------------------------
00525  * allow the user to change the APN. The API takes username and password
00526  * but they are not used.
00527  *
00528  * Input: apn string
00529  *        username - not used
00530  *        password - not used
00531  *
00532  * Output: none
00533  *
00534  * Return: nsapi_error_t 
00535  */
00536 nsapi_error_t WNC14A2AInterface::set_credentials(const char *apn, const char *username, const char *password) 
00537 {
00538     debugOutput(_debugUart,(char*)"+ENTER set_credentials()\n");
00539     if( !_pwnc ) 
00540         return (_errors=NSAPI_ERROR_NO_CONNECTION);
00541         
00542     if( !apn )
00543         return (_errors=NSAPI_ERROR_PARAMETER);
00544 
00545     if( !_pwnc->setApnName(apn) )
00546         return (_errors=NSAPI_ERROR_DEVICE_ERROR);
00547 
00548     return (_errors=NSAPI_ERROR_OK);
00549 }
00550 
00551 /*-------------------------------------------------------------------------
00552  * Register a callback on state change of the socket.FROM NetworkStack
00553  *  @param handle       Socket handle
00554  *  @param callback     Function to call on state change
00555  *  @param data         Argument to pass to callback
00556  *  @note Callback may be called in an interrupt context.
00557  */
00558 void WNC14A2AInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
00559 {
00560     debugOutput(_debugUart,(char*)"+CALLED socket_attach()\n");
00561 }
00562 
00563 /*-------------------------------------------------------------------------
00564  * check to see if we are currently regisered with the network.
00565  *
00566  * Input: none
00567  *
00568  * Output: none
00569  *
00570  * Return: ture if we are registerd, false if not or an error occured
00571  */
00572 bool WNC14A2AInterface::registered()
00573 {
00574     debugOutput(_debugUart,(char*)"+ENTER registered()\n");
00575     if( !_pwnc ) {
00576         _errors=NSAPI_ERROR_NO_CONNECTION;
00577         return false;
00578         }
00579 
00580     if ( _pwnc->getWncStatus() == WNC_GOOD ){
00581         _errors=NSAPI_ERROR_OK;
00582         return true;
00583         }
00584     _errors=NSAPI_ERROR_NO_CONNECTION;
00585     return false;
00586 }
00587 
00588 /*-------------------------------------------------------------------------
00589  * doDebug is just a handy way to allow a developer to set different levels
00590  * of debug for the WNC14A2A device.
00591  *
00592  * Input:  a Bitfield of -
00593  *   basic debug   = 0x01
00594  *   more debug    = 0x02
00595  *   network debug = 0x04
00596  *   all debug     = 0x07
00597  *
00598  * Output: none
00599  *
00600  * Returns: void
00601  */
00602 void WNC14A2AInterface::doDebug( int v )
00603 {
00604     if( !_pwnc )
00605         _errors = NSAPI_ERROR_DEVICE_ERROR;
00606     else
00607         _pwnc->enableDebug( (v&1), (v&2) );
00608 
00609     m_debug=(v&4);
00610     debugOutput(_debugUart,(char*)"+SETTING debug flag to 0x%02X\n",v);
00611 }
00612 
00613 /*-------------------------------------------------------------------------
00614  * Simple function to allow for writing debug messages.  It always 
00615  * checks to see if debug has been enabled or not before it
00616  * outputs the message.
00617  *
00618  * Input: The debug uart pointer followed by format string and vars
00619  *
00620  * Output: none
00621  *
00622  * Return: void
00623  */
00624 void WNC14A2AInterface::debugOutput(WNCDebug *dbgOut, char * format, ...) 
00625 {
00626     if( dbgOut && m_debug ) {
00627         char buffer[256];
00628         va_list args;
00629         va_start (args, format);
00630         vsnprintf(buffer, sizeof(buffer), format, args);
00631         dbgOut->puts(buffer);
00632         va_end (args);
00633         }
00634 }
00635 
00636 
00637 ////////////////////////////////////////////////////////////////////
00638 //  UDP methods
00639 ///////////////////////////////////////////////////////////////////
00640 
00641 //-------------------------------------------------------------------------
00642 //sends data to a UDP socket
00643 int WNC14A2AInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size)
00644 {
00645     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00646     
00647     debugOutput(_debugUart,(char*)"+CALLED socket_sendto()\n");
00648     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), fail);
00649     if (!wnc->opened) {
00650        int err = socket_connect(wnc, address);
00651        if (err < 0) 
00652            return err;
00653        }
00654     wnc->addr = address;
00655 
00656     return socket_send(wnc, data, size);
00657 }
00658 
00659 //receives from a UDP socket
00660 int WNC14A2AInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size)
00661 {
00662     WNCSOCKET *wnc = (WNCSOCKET *)handle;
00663     debugOutput(_debugUart,(char*)"+CALLED socket_recvfrom()\n");
00664     int ret = socket_recv(wnc, (char *)buffer, size);
00665     if (ret >= 0 && address) 
00666         *address = wnc->addr;
00667     return ret;
00668 }
00669 
00670 ////////////////////////////////////////////////////////////////////
00671 //  SMS methods
00672 ///////////////////////////////////////////////////////////////////
00673 
00674 /*-------------------------------------------------------------------------
00675  * IOTSMS message don't use a phone number, they use the device ICCID.  This 
00676  * function returns the ICCID based number that is used for this device.
00677  *
00678  * Input: none
00679  * Output: none
00680  * Return: string containing the IOTSMS number to use
00681  */
00682 char* WNC14A2AInterface::getSMSnbr( void ) 
00683 {
00684     char * ret=NULL;
00685     string iccid_str;
00686     static string msisdn_str;
00687 
00688     if( !_pwnc ) {
00689         _errors=NSAPI_ERROR_NO_CONNECTION;
00690         return NULL;
00691         }
00692 
00693     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
00694 
00695     if( !_pwnc->getICCID(&iccid_str) ) 
00696         return ret;
00697  
00698     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
00699 
00700     if( _pwnc->convertICCIDtoMSISDN(iccid_str, &msisdn_str) )
00701          ret = (char*)msisdn_str.c_str();    
00702     return ret;
00703 }
00704 
00705 
00706 /*-------------------------------------------------------------------------
00707  * Normally the user attaches his call-back function when performing
00708  * the listen call which enables the SMS system, but this function
00709  * allows them to update the callback if desired.
00710  *
00711  * input: pointer to the function to call
00712  * output: none
00713  * return: none
00714  */
00715 void WNC14A2AInterface::sms_attach(void (*callback)(IOTSMS *))
00716 {
00717     debugOutput(_debugUart,(char*)"+CALLED sms_attach() called\n");
00718     _sms_cb = callback;
00719 }
00720 
00721 /*-------------------------------------------------------------------------
00722  * Call this to start the SMS system.  It is needed to reset the WNC 
00723  * internal data structures related to SMS messaging
00724  */
00725 void WNC14A2AInterface::sms_start(void)
00726 {
00727     _pwnc_mutex.lock();                       //delete any message currently in storage
00728     _pwnc->deleteSMSTextFromMem('*');       //so we are notified of new incomming messages
00729     _pwnc_mutex.unlock();
00730 }
00731 
00732 /*-------------------------------------------------------------------------
00733  * Initialize the IoT SMS system.  Initializing it allows the user to set a 
00734  * polling period to check for SMS messages, and a SMS is recevied, then 
00735  * a user provided function is called.  
00736  *
00737  * Input: polling period in seconds. If not specified 30 seconds is used.
00738  *        pointer to a users calllback function
00739  * Output: none
00740  *
00741  * Returns: void
00742  */
00743 void WNC14A2AInterface::sms_listen(uint16_t pp)
00744 {
00745     debugOutput(_debugUart,(char*)"+CALLED sms_listen(%d) called\n",pp);
00746     if( !_pwnc ) {
00747         _errors=NSAPI_ERROR_NO_CONNECTION;
00748         return;
00749         }
00750 
00751     CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), fail);
00752 
00753     if( m_smsmoning )
00754         m_smsmoning = false;
00755     if( pp < 1)
00756         pp = 30;
00757 
00758 
00759     debugOutput(_debugUart,(char*)"+setup event queue\n");
00760     smsThread.start(callback(&sms_queue,&EventQueue::dispatch_forever));
00761 
00762     _pwnc_mutex.lock();                       //delete any message currently in storage
00763     _pwnc->deleteSMSTextFromMem('*');       //so we are notified of new incomming messages
00764     _pwnc_mutex.unlock();
00765     sms_queue.call_every(pp*1000, mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::handle_sms_event));
00766 
00767     m_smsmoning = true;
00768     debugOutput(_debugUart,(char*)"+EXIT sms_listen()\n");
00769 }
00770 
00771 /*-------------------------------------------------------------------------
00772  * process to check SMS messages that is called at the user specified period
00773  * 
00774  * input: none
00775  * output:none
00776  * return:void
00777  */
00778 void WNC14A2AInterface::handle_sms_event()
00779 {
00780     int msgs_available;
00781     debugOutput(_debugUart,(char*)"+CALLED handle_sms_event() called\n");
00782 
00783     if ( _sms_cb && m_smsmoning ) {
00784         CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), fail);
00785         _pwnc_mutex.lock();
00786         msgs_available = _pwnc->readUnreadSMSText(&m_smsmsgs, true);
00787         _pwnc_mutex.unlock();
00788         if( msgs_available ) {
00789             debugOutput(_debugUart,(char*)"+Have %d unread texts present\n",m_smsmsgs.msgCount);
00790             for( int i=0; i< m_smsmsgs.msgCount; i++ ) {
00791                 m_MsgText.number = m_smsmsgs.e[i].number;
00792                 m_MsgText.date = m_smsmsgs.e[i].date;
00793                 m_MsgText.time = m_smsmsgs.e[i].time;
00794                 m_MsgText.msg = m_smsmsgs.e[i].msg;
00795                 _sms_cb(&m_MsgText);
00796                 }
00797             }
00798         }
00799     debugOutput(_debugUart,(char*)"+EXIT handle_sms_event\n");
00800 }
00801 
00802 
00803 /*-------------------------------------------------------------------------
00804  * Check for any SMS messages that are present. If there are, then  
00805  * fetch them and pass to the users call-back function for processing
00806  *
00807  * input: pointer to a IOTSMS message buffer array (may be more than 1 msg)
00808  * output:message buffer pointer is updated
00809  * return: the number of messages being returned
00810  */
00811 int WNC14A2AInterface::getSMS(IOTSMS **pmsg) 
00812 {
00813     int msgs_available;
00814 
00815     debugOutput(_debugUart,(char*)"+CALLED getSMS()\n");
00816     CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), fail);
00817 
00818     _pwnc_mutex.lock();
00819     msgs_available = _pwnc->readUnreadSMSText(&m_smsmsgs, true);
00820     _pwnc_mutex.unlock();
00821 
00822     if( msgs_available ) {
00823         debugOutput(_debugUart,(char*)"+Have %d unread texts present\n",m_smsmsgs.msgCount);
00824         for( int i=0; i< m_smsmsgs.msgCount; i++ ) {
00825             m_MsgText_array[i].number = m_smsmsgs.e[i].number;
00826             m_MsgText_array[i].date   = m_smsmsgs.e[i].date;
00827             m_MsgText_array[i].time   = m_smsmsgs.e[i].time;
00828             m_MsgText_array[i].msg    = m_smsmsgs.e[i].msg;
00829             pmsg[i] = (IOTSMS*)&m_MsgText_array[i];
00830             }
00831         debugOutput(_debugUart,(char*)"+DONE getting messages\n");
00832         msgs_available = m_smsmsgs.msgCount;
00833         }
00834     debugOutput(_debugUart,(char*)"+EXIT getSMS\n");
00835     return msgs_available;
00836 }
00837 
00838 
00839 /*-------------------------------------------------------------------------
00840  * send a message to the specified user number. 
00841  *
00842  * input: string containing users number
00843  *        string with users message
00844  * ouput: none
00845  *
00846  * return: true if no problems occures, false if failed to send
00847  */
00848 int WNC14A2AInterface::sendIOTSms(const string& number, const string& message) 
00849 {
00850 
00851     debugOutput(_debugUart,(char*)"+CALLED sendIOTSms(%s,%s)\n",number.c_str(), message.c_str());
00852     _pwnc_mutex.lock();
00853     int i =  _pwnc->sendSMSText((char*)number.c_str(), message.c_str());
00854     _pwnc_mutex.unlock();
00855 
00856     return i;
00857 }
00858 
00859 //
00860 //-------------------------------------------------------------------------
00861 //-------------------------------------------------------------------------
00862 //-------------------------------------------------------------------------
00863 //      NetworkStack API's that are not support in the WNC14A2A
00864 //-------------------------------------------------------------------------
00865 //-------------------------------------------------------------------------
00866 //-------------------------------------------------------------------------
00867 //
00868 
00869 int inline WNC14A2AInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) 
00870 {
00871     debugOutput(_debugUart,(char*)"+CALLED socket_accept()\n");
00872     _errors = NSAPI_ERROR_UNSUPPORTED;
00873     return -1;
00874 }
00875 
00876 int inline WNC14A2AInterface::socket_bind(void *handle, const SocketAddress &address) 
00877 {
00878     debugOutput(_debugUart,(char*)"+CALLED socket_bind()\n");
00879     _errors = NSAPI_ERROR_UNSUPPORTED;
00880     return -1;
00881 }
00882 
00883 
00884 int inline WNC14A2AInterface::socket_listen(void *handle, int backlog)
00885 {
00886    debugOutput(_debugUart,(char*)"+CALLED socket_listen()\n");
00887     _errors = NSAPI_ERROR_UNSUPPORTED;
00888     return -1;
00889 }
00890