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

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).

To demonstrate the use of the Interface, a series of example programs have been provided. Links to these examples are provided below. All examples can be compiled using both the on-line compiler and the ARMmbed CLI (command line interface, see https://github.com/ARMmbed/mbed-cli)

NOTE: This library/class is specific to the AT&T Cellular IoT Starter Kit which uses a FRDM-K64F. The users mbed.org compiler should be configured to use the FRDM-K64F platform.

Example Programs

Import the example programs below and follow the README.md in each to run the example program.

  • several examples of the interface using easy_connect.
  • SMS demonstration program that demonstrates SMS usage
  • Sockets demonstration program demonstrating using TCP sockets to interact with others
  • As new example program are developed, this README will be updated

WNC FIRMWARE VERSION

The WNC14A2AInterface class currently supports the following version(s):

  • MPSS: M14A2A_v11.21.162331 APSS: M14A2A_v11.27.162331

License

This library is released under the Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License and may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Files at this revision

API Documentation at this revision

Comitter:
JMF
Date:
Tue Apr 18 00:05:54 2017 +0000
Parent:
0:d6cb9ca0bae4
Child:
2:9ee51d19d670
Commit message:
Added README file.

Changed in this revision

README.md Show annotated file Show diff for this revision Revisions of this file
WNC14A2AInterface.cpp Show annotated file Show diff for this revision Revisions of this file
WNC14A2AInterface.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md	Tue Apr 18 00:05:54 2017 +0000
@@ -0,0 +1,38 @@
+Use this inteface to connect to and interact with the WNC M14A2A LTE Ceullar 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).
+
+To demonstrate the use of the Interface, a series of example programs have been provided.  Links to these examples
+are provided below.  All examples can be compiled using both the on-line compiler and the ARMmbed CLI (command line 
+interface, see https://github.com/ARMmbed/mbed-cli)
+
+**NOTE**: This library/class is specific to the AT&T Cellular IoT Starter Kit which uses a FRDM-K64F.  The users mbed.org
+compiler should be configured to use the FRDM-K64F platform.
+
+Example Programs
+================
+
+Import the example programs below and follow the README.md in each to run the example program.
+
+  * several examples of the interface using easy_connect.
+  * SMS demonstration program that demonstrates SMS usage
+  * Sockets demonstration program demonstrating using tcp sockets to interact with others
+  * As new example program are developed, this readme will be updated
+
+WNC FIRWARE VERSION
+===================
+
+The WNCInterface class currently supports the following version(s):
+* MPSS: M14A2A_v11.21.162331 APSS: M14A2A_v11.27.162331
+
+License
+=======
+This library is released under the    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+file except in compliance with the License and may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
+language governing permissions and limitations under the License.
+
--- a/WNC14A2AInterface.cpp	Mon Apr 17 23:59:13 2017 +0000
+++ b/WNC14A2AInterface.cpp	Tue Apr 18 00:05:54 2017 +0000
@@ -0,0 +1,882 @@
+
+#include "WNC14A2AInterface.h"
+#include <Thread.h>
+#include <string> 
+
+/** WNC14A2AInterface class
+ *  Implementation of the NetworkInterface for the AT&T IoT Starter Kit 
+ *  based on the WNC 14A2A LTE Data Module
+ */
+
+#define WNC14A2A_MISC_TIMEOUT 3000
+#define WNC14A2A_RESTART_TIMEOUT 10000
+#define WNC14A2A_COMMUNICATION_TIMEOUT 100
+#define READ_EVERYMS    500
+
+/////////////////////////////////////////////////////
+// NXP GPIO Pins that are used to initialize the WNC Shield
+/////////////////////////////////////////////////////
+DigitalOut  mdm_uart2_rx_boot_mode_sel(PTC17);  // on powerup, 0 = boot mode, 1 = normal boot
+DigitalOut  mdm_power_on(PTB9);                 // 0 = modem on, 1 = modem off (hold high for >5 seconds to cycle modem)
+DigitalOut  mdm_wakeup_in(PTC2);                // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield
+DigitalOut  mdm_reset(PTC12);                   // active high
+DigitalOut  shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active
+DigitalOut  mdm_uart1_cts(PTD0);
+
+// Define pin associations for the controller class to use be careful to 
+//  keep the order of the pins in the initialization list.
+
+using namespace WncControllerK64F_fk;       // namespace for the controller class use
+
+WncGpioPinListK64F wncPinList = { 
+    &mdm_uart2_rx_boot_mode_sel,
+    &mdm_power_on,
+    &mdm_wakeup_in,
+    &mdm_reset,
+    &shield_3v3_1v8_sig_trans_ena,
+    &mdm_uart1_cts
+};
+
+Thread smsThread;
+static Mutex _pwnc_mutex;
+
+static WNCSOCKET _sockets[WNC14A2A_SOCKET_COUNT];
+BufferedSerial mdmUart(PTD3,PTD2,1024,1);       //UART for WNC Module
+
+//-------------------------------------------------------------------------
+//
+// Class constructor.  May be invoked with or without the APN and/or pointer
+// to a debug output.  After the constructor has completed, the user can 
+// check _errors to determine if any errors occured during instanciation.
+// _errors = 0 when no errors occured
+//           1 when power-on error occured
+//           2 when settng the APN error occured
+//           4 when unable to get the network configuration
+//           8 when allocating a new WncControllerK64F object failed
+//          NSAPI_ERROR_UNSUPPORTED when attempting to create a second object
+//
+
+WNC14A2AInterface::WNC14A2AInterface(BufferedSerial *_dbg) : 
+ m_wncpoweredup(0),
+ _pwnc(NULL),
+ m_active_socket(-1),
+ m_smsmoning(0)
+{
+    _errors = NSAPI_ERROR_OK;
+    
+    m_debug=false;
+
+    if( _pwnc ) { //can only have a single instance of class
+        _errors =  NSAPI_ERROR_UNSUPPORTED;
+        return;
+        }
+    for( int i=0; i<WNC14A2A_SOCKET_COUNT; i++ ) {
+        _sockets[i].socket = i;
+        _sockets[i].addr = NULL;
+        _sockets[i].opened=false;
+        _sockets[i].proto=NSAPI_TCP;
+        }
+
+    
+    memset(_mac_address,0x00,sizeof(_mac_address));
+
+    _debugUart = _dbg;
+    if( _dbg != NULL ) {
+        _dbg->printf("Adding DEBUG output\n");
+        _pwnc = new WncControllerK64F(&wncPinList, &mdmUart, _dbg);
+        m_debug=true;
+        if( _pwnc ) 
+            _pwnc->enableDebug(1,1);
+        }
+    else 
+        _pwnc = new WncControllerK64F_fk::WncControllerK64F(&wncPinList, &mdmUart, NULL);
+        
+    if( !_pwnc ) {
+        debugOutput(_debugUart,(char*)", FAILED!\n");
+        _errors = NSAPI_ERROR_DEVICE_ERROR;
+        }
+    else
+        debugOutput(_debugUart, (char*)"\n");
+}
+
+/*-------------------------------------------------------------------------
+ * standard destructor... free up allocated memory
+ */
+
+WNC14A2AInterface::~WNC14A2AInterface()
+{
+    delete _pwnc;  //free the existing WncControllerK64F object
+}
+
+nsapi_error_t WNC14A2AInterface::connect() 
+{
+    debugOutput(_debugUart,(char*)"+CALLED connect(void)\n");
+    return connect(NULL,NULL,NULL);
+}
+
+/*-------------------------------------------------------------------------
+ * This call powers up the WNC module and connects to the user specified APN.  If no APN is provided
+ * a default one of 'm2m.com.attz' will be used (the NA APN)
+ *
+ * Input: *apn is the APN string to use
+ *        *username - NOT CURRENTLY USED
+ *        *password - NOT CURRENTLY USED
+ *
+ * Output: none
+ *
+ * Return: nsapi_error_t
+ */
+nsapi_error_t WNC14A2AInterface::connect(const char *apn, const char *username, const char *password) 
+{
+    debugOutput(_debugUart,(char*)"+ENTER connect(apn,user,pass)\n");
+    if( !_pwnc )
+        return (_errors=NSAPI_ERROR_NO_CONNECTION);
+
+    if (!apn)
+        apn = "m2m.com.attz";
+
+    if (!m_wncpoweredup) {
+        debugOutput(_debugUart,(char*)"+call powerWncOn using '%s'\n",apn);
+        _pwnc_mutex.lock();
+        m_wncpoweredup=_pwnc->powerWncOn(apn,40);
+        _pwnc_mutex.unlock();
+        _errors = m_wncpoweredup? 1:0;
+        }
+    else { //we've already called powerWncOn and set the APN, so just set the APN 
+        debugOutput(_debugUart,(char*)"+already powered on, set APN to: %s\n",apn);
+        _pwnc_mutex.lock();
+        _errors = _pwnc->setApnName(apn)? 1:0;
+        _pwnc_mutex.unlock();
+        }
+
+    _pwnc_mutex.lock();
+    _errors |= _pwnc->getWncNetworkingStats(&myNetStats)? 2:0;
+    _pwnc_mutex.unlock();
+
+    debugOutput(_debugUart,(char*)"+EXIT connect %02X\n",_errors);
+    return (!_errors)? NSAPI_ERROR_NO_CONNECTION : NSAPI_ERROR_OK;
+}
+
+/*--------------------------------------------------------------------------
+ * This function calls the WNC to retrieve the device (this WNC) connected IP 
+ * address once we are connected to the APN.
+ *
+ * Inputs: NONE.
+ *
+ * Output: none.
+ *
+ * Return: pointer to the IP string or NULL 
+ */
+const char *WNC14A2AInterface::get_my_ip_address()
+{
+    const char *ptr=NULL; 
+
+    _pwnc_mutex.lock();
+    if ( _pwnc->getWncNetworkingStats(&myNetStats) ) {
+        CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
+        ptr = &myNetStats.ip[0];
+    }
+    _pwnc_mutex.unlock();
+    _errors=NSAPI_ERROR_NO_CONNECTION;
+    return ptr;
+}
+
+/*--------------------------------------------------------------------------
+ * This function calls the WNC to retrieve the currently connected IP address
+ * it will be a bogus 192.168.0.1 if we are not connected to anyone
+ *
+ * Inputs: NONE.
+ *
+ * Output: none.
+ *
+ * Return: pointer to the IP string or NULL 
+ */
+const char *WNC14A2AInterface::get_ip_address()
+{
+    static char *ptr=NULL, ipAddrStr[25];
+    debugOutput(_debugUart,(char*)"+ENTER get_ip_address()\n");
+
+    memset(ipAddrStr, 0x00, sizeof(ipAddrStr));
+    _pwnc_mutex.lock();
+
+    if( _pwnc && m_active_socket != -1 )
+        if( _pwnc->getIpAddr(m_active_socket, ipAddrStr) )
+          ptr=ipAddrStr;
+    _pwnc_mutex.unlock();
+    _errors=NSAPI_ERROR_NO_CONNECTION;
+    return ptr;
+}
+
+/* -------------------------------------------------------------------------
+ * Open a socket for the WNC.  This doesn't actually open the socket within
+ * the WNC, it only allocates a socket device and saves the pertinet info
+ * that will be required with the WNC socket is opened. The m_active_socket
+ * is also updated to this socket as it is assumed this socket should be used
+ * for subsequent interactions.
+ *
+ * Input: 
+ *  - a pointer to a handle pointer.  
+ *  - The type of socket this will be, either NSAPI_UDP or NSAP_TCP
+ *
+ * Output: *handle is updated
+ *
+ * Return:
+ *  - socket being used if successful, -1 on failure
+ */
+int WNC14A2AInterface::socket_open(void **handle, nsapi_protocol_t proto) 
+{
+    int i;
+    debugOutput(_debugUart,(char*)"+ENTER socket_open()\n");
+
+    // search through the available sockets (WNC can only support a max amount).
+    for( i=0; i<WNC14A2A_SOCKET_COUNT; i++ )
+        if( !_sockets[i].opened )
+            break;
+
+    if( i == WNC14A2A_SOCKET_COUNT ) {
+        _errors=NSAPI_ERROR_NO_SOCKET;
+        return -1;
+        }
+
+    m_active_socket = i;           
+    _sockets[i].socket = i;        //save this index to make easier later-on
+    _sockets[i].url="";
+    _sockets[i].opened = true;     //ok, we are using this socket now
+    _sockets[i].addr = NULL;       //but we haven't opened it yet
+    _sockets[i].proto = (proto == NSAPI_UDP) ? 0 : 1; //set it up for what WNC wants
+    *handle = &_sockets[i];
+
+    debugOutput(_debugUart,(char*)"+USING Socket index %d, OPEN=%s, proto =%d\nEXIT socket_open()\n",
+    i, _sockets[i].opened?"YES":"NO", _sockets[i].proto);
+    
+    _errors = NSAPI_ERROR_OK;
+    return i;
+}
+
+/*-------------------------------------------------------------------------
+ * Connect a socket to a IP/PORT.  Before you can connect a socket, you must have opened
+ * it.
+ *
+ * Input: handle - pointer to the socket to use
+ *        address- the IP/Port pair that will be used
+ *
+ * Output: none
+ *
+ * return: 0 or greater on success (value is the socket ID)
+ *        -1 on failure
+ */
+int WNC14A2AInterface::socket_connect(void *handle, const SocketAddress &address) 
+{
+    WNCSOCKET *wnc = (WNCSOCKET *)handle;   
+
+    debugOutput(_debugUart,(char*)"+ENTER socket_connect()\n");
+    debugOutput(_debugUart,(char*)"+IP  = %s\n+PORT= %d\n", address.get_ip_address(), address.get_port());
+    
+    if (!_pwnc || m_active_socket == -1) {
+        _errors = NSAPI_ERROR_NO_SOCKET;
+        return -1;
+        }
+
+    if( !wnc->opened ) {
+        _errors = NSAPI_ERROR_NO_SOCKET;
+        return -1;
+        }
+    m_active_socket = wnc->socket;  //in case the user is asking for a different socket
+    wnc->addr = address;
+                                
+    //we will always connect using the URL if possible, if no url has been provided, try the IP address
+    if( wnc->url.empty() ) {
+        debugOutput(_debugUart,(char*)"+call openSocketIpAddr(%d,%s,%d,%d)\n",m_active_socket, 
+                           address.get_ip_address(), address.get_port(), wnc->proto);
+        if( !_pwnc->openSocketIpAddr(m_active_socket, address.get_ip_address(), address.get_port(), 
+                                 wnc->proto, WNC14A2A_COMMUNICATION_TIMEOUT) ) {
+            _errors = NSAPI_ERROR_NO_SOCKET;
+            return -1;
+            }
+        }
+     else {
+        debugOutput(_debugUart,(char*)"+call openSocketUrl(%d,%s,%d,%d)\n", m_active_socket, 
+                           wnc->url.c_str(), wnc->addr.get_port(), wnc->proto);
+        if( !_pwnc->openSocketUrl(m_active_socket, wnc->url.c_str(), wnc->addr.get_port(), wnc->proto) ) {
+            _errors = NSAPI_ERROR_NO_SOCKET;
+            return -1;
+            }
+        }
+
+    debugOutput(_debugUart,(char*)"+SOCKET %d CONNECTED!\n+URL=%s\n+IP=%s; PORT=%d\n+EXIT socket_connect()\n\n",m_active_socket,
+                wnc->url.c_str(), wnc->addr.get_ip_address(), wnc->addr.get_port());
+    return 0;
+}
+
+/*-------------------------------------------------------------------------
+ * Perform a URL name resolve, update the IP/Port pair, and nsapi_version. nsapi_version
+ * could be either NSAPI_IPv4 or NSAPI_IPv6 but this functional is hard coded ti NSAPI_IPv4
+ * for now. The currently active socket is used for the resolution.  
+ *
+ * Input: name - the URL to resolve
+ *
+ * Output: address - the IP/PORT pair this URL resolves to
+ *         version - always assumed to be NSAPI_IPv4  currently
+ *
+ * Return: nsapi_error_t
+ */
+
+nsapi_error_t WNC14A2AInterface::gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version)
+{
+    nsapi_error_t ret = NSAPI_ERROR_OK;
+    char ipAddrStr[25];
+
+    debugOutput(_debugUart,(char*)"+ENTER gethostbyname()()\n+CURRENTLY:\n");
+    debugOutput(_debugUart,(char*)"+URL = %s\n+IP  = %s\n+PORT= %d\n", name, address->get_ip_address(), address->get_port());
+    memset(ipAddrStr,0x00,sizeof(ipAddrStr));
+    
+    if (!_pwnc || m_active_socket == -1) 
+        return (_errors = NSAPI_ERROR_NO_SOCKET);
+
+    //Execute DNS query.  
+    if( !_pwnc->resolveUrl(m_active_socket, name) )  
+        return (_errors = NSAPI_ERROR_DEVICE_ERROR);
+
+    //Now, get the IP address that the URL was resolved to
+    if( !_pwnc->getIpAddr(m_active_socket, ipAddrStr) )
+        return (_errors = NSAPI_ERROR_DEVICE_ERROR);
+
+    _sockets[m_active_socket].url=name;
+    _sockets[m_active_socket].addr.set_ip_address(ipAddrStr);
+    address->set_ip_address(ipAddrStr);
+
+    debugOutput(_debugUart,(char*)"+resolveUrl returned IP=%s\n",ipAddrStr);
+    debugOutput(_debugUart,(char*)"+EXIT gethostbyname()\n+URL = %s\n+IP  = %s\n+PORT= %d\n\n", 
+                _sockets[m_active_socket].url.c_str(), address->get_ip_address(), 
+                address->get_port());
+    _errors = ret;
+    return ret;
+}
+ 
+/*-------------------------------------------------------------------------
+ * using the specified socket, send the data.
+ *
+ * Input: handle of the socket to use
+ *        pointer to the data to send
+ *        amount of data being sent
+ *
+ * Output: none
+ *
+ * Return: number of bytes that was sent
+ */
+int WNC14A2AInterface::socket_send(void *handle, const void *data, unsigned size) 
+{
+    WNCSOCKET *wnc = (WNCSOCKET *)handle;
+    int r = -1;
+    debugOutput(_debugUart,(char*)"+ENTER socket_send()\n");
+
+    if (!_pwnc || m_active_socket == -1) {
+        _errors = NSAPI_ERROR_NO_SOCKET;
+        return 0;
+        }
+    else
+        m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
+
+    debugOutput(_debugUart,(char*)"+SOCKET %d is %s, URL=%s, IP=%s, PORT=%d\n",m_active_socket,
+        (char*)wnc->opened?"OPEN":"CLOSED",wnc->url.c_str(),wnc->addr.get_ip_address(),wnc->addr.get_port());
+    debugOutput(_debugUart,(char*)"+WRITE [%s] (%d bytes) to socket #%d\n",data,size,wnc->socket);
+
+    _pwnc_mutex.lock();
+    if( _pwnc->write(m_active_socket, (const uint8_t*)data, size) ) 
+       r = size;
+    else
+       debugOutput(_debugUart,(char*)"+ERROR: write to socket %d failed!\n",m_active_socket);
+    _pwnc_mutex.unlock();
+
+    debugOutput(_debugUart,(char*)"+EXIT socket_send(), successful: %d\n\n",r);
+    return r;
+}  
+
+/*-------------------------------------------------------------------------
+ * Called to receive data.  
+ *
+ * Input: handle to the socket we want to read from
+ *
+ * Output: data we receive is placed into the data buffer
+ *         size is the size of the buffer
+ *
+ * Returns: The number of bytes received or -1 if an error occured
+ */
+int WNC14A2AInterface::socket_recv(void *handle, void *data, unsigned size) 
+{
+    WNCSOCKET *wnc = (WNCSOCKET *)handle;
+    size_t done, cnt;
+    Timer t;
+
+    debugOutput(_debugUart,(char*)"+ENTER socket_recv(); read up to %d bytes\n",size);
+
+    memset(data,0x00,size);  
+    if (!_pwnc || m_active_socket == -1) {
+        _errors = NSAPI_ERROR_NO_SOCKET;
+        return -1;
+        }
+    else
+        m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
+
+    t.start();
+    do {
+        if( !(t.read_ms() % READ_EVERYMS) )
+          cnt = done = _pwnc->read(m_active_socket, (uint8_t *)data, (uint32_t) size);
+        done = (cnt || (t.read_ms() > WNC14A2A_MISC_TIMEOUT))? 1:0;
+        }
+    while( !done );
+    t.stop();
+    
+    if( _pwnc->getWncStatus() != WNC_GOOD ) {
+        _errors = NSAPI_ERROR_DEVICE_ERROR;
+        return -1;
+        }
+
+    debugOutput(_debugUart,(char*)"+EXIT socket_recv(), ret=%d\n",cnt);
+    return cnt;
+}
+
+/*-------------------------------------------------------------------------
+ * Close a socket 
+ *
+ * Input: the handle to the socket to close
+ *
+ * Output: none
+ *
+ * Return: -1 on error, otherwise 0
+ */
+int WNC14A2AInterface::socket_close(void *handle)
+{
+    WNCSOCKET *wnc = (WNCSOCKET*)handle;
+    debugOutput(_debugUart,(char*)"+CALLED socket_close()\n");
+
+    if (!_pwnc || m_active_socket == -1) {
+        _errors = NSAPI_ERROR_NO_SOCKET;
+        return -1;
+        }
+    else
+        m_active_socket = wnc->socket; //just in case sending to a socket that wasn't last used
+    
+    if( !_pwnc->closeSocket(m_active_socket) ) {
+        _errors = NSAPI_ERROR_DEVICE_ERROR;
+        return -1;
+        }
+
+    wnc->opened = false;     //no longer in use
+    wnc->addr = NULL;        //not open
+    wnc->proto = 0;  //assume TCP for now
+    _errors = NSAPI_ERROR_OK;
+    return 0;
+}
+
+/*-------------------------------------------------------------------------
+ * return the MAC for this device.  Because there is no MAC Ethernet 
+ * address to return, this function returns a bogus MAC address created 
+ * from the ICCD on the SIM that is being used.
+ *
+ * Input: none
+ *
+ * Output: none
+ *
+ * Return: MAC string containing "NN:NN:NN:NN:NN:NN" or NULL
+ */
+const char *WNC14A2AInterface::get_mac_address()
+{
+    string mac, str;
+    debugOutput(_debugUart,(char*)"+ENTER get_mac_address()\n");
+
+    if( _pwnc->getICCID(&str) ) {
+        CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), null);
+        mac = str.substr(3,20);
+        mac[2]=mac[5]=mac[8]=mac[11]=mac[14]=':';
+        strncpy(_mac_address, mac.c_str(), mac.length());
+        return _mac_address;
+    }
+    return NULL;
+}
+
+/*-------------------------------------------------------------------------
+ * return a pointer to the current WNC14A2AInterface
+ */
+NetworkStack *WNC14A2AInterface::get_stack() {
+    debugOutput(_debugUart,(char*)"+CALLED get_stack()\n");
+    return this;
+}
+
+/*-------------------------------------------------------------------------
+ * Disconnnect from the 14A2A, but we can not do that
+ * so just return saying everything is ok.
+ */
+nsapi_error_t WNC14A2AInterface::disconnect() 
+{
+    debugOutput(_debugUart,(char*)"+CALLED disconnect()\n");
+    return NSAPI_ERROR_OK;
+}
+
+/*-------------------------------------------------------------------------
+ * allow the user to change the APN. The API takes username and password
+ * but they are not used.
+ *
+ * Input: apn string
+ *        username - not used
+ *        password - not used
+ *
+ * Output: none
+ *
+ * Return: nsapi_error_t 
+ */
+nsapi_error_t WNC14A2AInterface::set_credentials(const char *apn, const char *username, const char *password) 
+{
+    debugOutput(_debugUart,(char*)"+ENTER set_credentials()\n");
+    if( !_pwnc ) 
+        return (_errors=NSAPI_ERROR_NO_CONNECTION);
+        
+    if( !apn )
+        return (_errors=NSAPI_ERROR_PARAMETER);
+
+    if( !_pwnc->setApnName(apn) )
+        return (_errors=NSAPI_ERROR_DEVICE_ERROR);
+
+    return (_errors=NSAPI_ERROR_OK);
+}
+
+/*-------------------------------------------------------------------------
+ * Register a callback on state change of the socket.FROM NetworkStack
+ *  @param handle       Socket handle
+ *  @param callback     Function to call on state change
+ *  @param data         Argument to pass to callback
+ *  @note Callback may be called in an interrupt context.
+ */
+void WNC14A2AInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
+{
+    debugOutput(_debugUart,(char*)"+CALLED socket_attach()\n");
+}
+
+/*-------------------------------------------------------------------------
+ * check to see if we are currently regisered with the network.
+ *
+ * Input: none
+ *
+ * Output: none
+ *
+ * Return: ture if we are registerd, false if not or an error occured
+ */
+bool WNC14A2AInterface::registered()
+{
+    debugOutput(_debugUart,(char*)"+ENTER registered()\n");
+    if( !_pwnc ) {
+        _errors=NSAPI_ERROR_NO_CONNECTION;
+        return false;
+        }
+
+    if ( _pwnc->getWncStatus() == WNC_GOOD ){
+        _errors=NSAPI_ERROR_OK;
+        return true;
+        }
+    _errors=NSAPI_ERROR_NO_CONNECTION;
+    return false;
+}
+
+/*-------------------------------------------------------------------------
+ * doDebug is just a handy way to allow a developer to set different levels
+ * of debug for the WNC14A2A device.
+ *
+ * Input:  a Bitfield of -
+ *   basic debug   = 0x01
+ *   more debug    = 0x02
+ *   network debug = 0x04
+ *   all debug     = 0x07
+ *
+ * Output: none
+ *
+ * Returns: void
+ */
+void WNC14A2AInterface::doDebug( int v )
+{
+    if( !_pwnc )
+        _errors = NSAPI_ERROR_DEVICE_ERROR;
+    else
+        _pwnc->enableDebug( (v&1), (v&2) );
+
+    m_debug=(v&4);
+    debugOutput(_debugUart,(char*)"+SETTING debug flag to 0x%02X\n",v);
+}
+
+/*-------------------------------------------------------------------------
+ * Simple function to allow for writing debug messages.  It always 
+ * checks to see if debug has been enabled or not before it
+ * outputs the message.
+ *
+ * Input: The debug uart pointer followed by format string and vars
+ *
+ * Output: none
+ *
+ * Return: void
+ */
+void WNC14A2AInterface::debugOutput(BufferedSerial *dbgOut, char * format, ...) 
+{
+    if( dbgOut && m_debug ) {
+        char buffer[256];
+        va_list args;
+        va_start (args, format);
+        vsnprintf(buffer, sizeof(buffer), format, args);
+        dbgOut->puts(buffer);
+        va_end (args);
+        }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//  UDP methods
+///////////////////////////////////////////////////////////////////
+
+//-------------------------------------------------------------------------
+//sends data to a UDP socket
+int WNC14A2AInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size)
+{
+    WNCSOCKET *wnc = (WNCSOCKET *)handle;
+    
+    debugOutput(_debugUart,(char*)"+CALLED socket_sendto()\n");
+    CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), fail);
+    if (!wnc->opened) {
+       int err = socket_connect(wnc, address);
+       if (err < 0) 
+           return err;
+       }
+    wnc->addr = address;
+
+    return socket_send(wnc, data, size);
+}
+
+//receives from a UDP socket
+int WNC14A2AInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size)
+{
+    WNCSOCKET *wnc = (WNCSOCKET *)handle;
+    debugOutput(_debugUart,(char*)"+CALLED socket_recvfrom()\n");
+    int ret = socket_recv(wnc, (char *)buffer, size);
+    if (ret >= 0 && address) 
+        *address = wnc->addr;
+    return ret;
+}
+
+////////////////////////////////////////////////////////////////////
+//  SMS methods
+///////////////////////////////////////////////////////////////////
+
+/*-------------------------------------------------------------------------
+ * IOTSMS message don't use a phone number, they use the device ICCID.  This 
+ * function returns the ICCID based number that is used for this device.
+ *
+ * Input: none
+ * Output: none
+ * Return: string containing the IOTSMS number to use
+ */
+char* WNC14A2AInterface::getSMSnbr( void ) 
+{
+    char * ret=NULL;
+    string iccid_str;
+    static string msisdn_str;
+
+    if( !_pwnc ) {
+        _errors=NSAPI_ERROR_NO_CONNECTION;
+        return NULL;
+        }
+
+    CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
+
+    if( !_pwnc->getICCID(&iccid_str) ) 
+        return ret;
+ 
+    CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), null);
+
+    if( _pwnc->convertICCIDtoMSISDN(iccid_str, &msisdn_str) )
+         ret = (char*)msisdn_str.c_str();    
+    return ret;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Normally the user attaches his call-back function when performing
+ * the listen call which enables the SMS system, but this function
+ * allows them to update the callback if desired.
+ *
+ * input: pointer to the function to call
+ * output: none
+ * return: none
+ */
+void WNC14A2AInterface::sms_attach(void (*callback)(IOTSMS *))
+{
+    debugOutput(_debugUart,(char*)"+CALLED sms_attach() called\n");
+    _sms_cb = callback;
+}
+
+/*-------------------------------------------------------------------------
+ * Call this to start the SMS system.  It is needed to reset the WNC 
+ * internal data structures related to SMS messaging
+ */
+void WNC14A2AInterface::sms_start(void)
+{
+    _pwnc_mutex.lock();                       //delete any message currently in storage
+    _pwnc->deleteSMSTextFromMem('*');       //so we are notified of new incomming messages
+    _pwnc_mutex.unlock();
+}
+
+/*-------------------------------------------------------------------------
+ * Initialize the IoT SMS system.  Initializing it allows the user to set a 
+ * polling period to check for SMS messages, and a SMS is recevied, then 
+ * a user provided function is called.  
+ *
+ * Input: polling period in seconds. If not specified 30 seconds is used.
+ *        pointer to a users calllback function
+ * Output: none
+ *
+ * Returns: void
+ */
+void WNC14A2AInterface::sms_listen(uint16_t pp)
+{
+    debugOutput(_debugUart,(char*)"+CALLED sms_listen(%d) called\n",pp);
+    if( !_pwnc ) {
+        _errors=NSAPI_ERROR_NO_CONNECTION;
+        return;
+        }
+
+    CHK_WNCFE(( _pwnc->getWncStatus() == FATAL_FLAG ), fail);
+
+    if( m_smsmoning )
+        m_smsmoning = false;
+    if( pp < 1)
+        pp = 30;
+
+
+    debugOutput(_debugUart,(char*)"+setup event queue\n");
+    smsThread.start(callback(&sms_queue,&EventQueue::dispatch_forever));
+
+    _pwnc_mutex.lock();                       //delete any message currently in storage
+    _pwnc->deleteSMSTextFromMem('*');       //so we are notified of new incomming messages
+    _pwnc_mutex.unlock();
+    sms_queue.call_every(pp*1000, mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::handle_sms_event));
+
+    m_smsmoning = true;
+    debugOutput(_debugUart,(char*)"+EXIT sms_listen()\n");
+}
+
+/*-------------------------------------------------------------------------
+ * process to check SMS messages that is called at the user specified period
+ * 
+ * input: none
+ * output:none
+ * return:void
+ */
+void WNC14A2AInterface::handle_sms_event()
+{
+    int msgs_available;
+    debugOutput(_debugUart,(char*)"+CALLED handle_sms_event() called\n");
+
+    if ( _sms_cb && m_smsmoning ) {
+        CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), fail);
+        _pwnc_mutex.lock();
+        msgs_available = _pwnc->readUnreadSMSText(&m_smsmsgs, true);
+        _pwnc_mutex.unlock();
+        if( msgs_available ) {
+            debugOutput(_debugUart,(char*)"+Have %d unread texts present\n",m_smsmsgs.msgCount);
+            for( int i=0; i< m_smsmsgs.msgCount; i++ ) {
+                m_MsgText.number = m_smsmsgs.e[i].number;
+                m_MsgText.date = m_smsmsgs.e[i].date;
+                m_MsgText.time = m_smsmsgs.e[i].time;
+                m_MsgText.msg = m_smsmsgs.e[i].msg;
+                _sms_cb(&m_MsgText);
+                }
+            }
+        }
+    debugOutput(_debugUart,(char*)"+EXIT handle_sms_event\n");
+}
+
+
+/*-------------------------------------------------------------------------
+ * Check for any SMS messages that are present. If there are, then  
+ * fetch them and pass to the users call-back function for processing
+ *
+ * input: pointer to a IOTSMS message buffer array (may be more than 1 msg)
+ * output:message buffer pointer is updated
+ * return: the number of messages being returned
+ */
+int WNC14A2AInterface::getSMS(IOTSMS **pmsg) 
+{
+    int msgs_available;
+
+    debugOutput(_debugUart,(char*)"+CALLED getSMS()\n");
+    CHK_WNCFE((_pwnc->getWncStatus()==FATAL_FLAG), fail);
+
+    _pwnc_mutex.lock();
+    msgs_available = _pwnc->readUnreadSMSText(&m_smsmsgs, true);
+    _pwnc_mutex.unlock();
+
+    if( msgs_available ) {
+        debugOutput(_debugUart,(char*)"+Have %d unread texts present\n",m_smsmsgs.msgCount);
+        for( int i=0; i< m_smsmsgs.msgCount; i++ ) {
+            m_MsgText_array[i].number = m_smsmsgs.e[i].number;
+            m_MsgText_array[i].date   = m_smsmsgs.e[i].date;
+            m_MsgText_array[i].time   = m_smsmsgs.e[i].time;
+            m_MsgText_array[i].msg    = m_smsmsgs.e[i].msg;
+            pmsg[i] = (IOTSMS*)&m_MsgText_array[i];
+            }
+        debugOutput(_debugUart,(char*)"+DONE getting messages\n");
+        msgs_available = m_smsmsgs.msgCount;
+        }
+    debugOutput(_debugUart,(char*)"+EXIT getSMS\n");
+    return msgs_available;
+}
+
+
+/*-------------------------------------------------------------------------
+ * send a message to the specified user number. 
+ *
+ * input: string containing users number
+ *        string with users message
+ * ouput: none
+ *
+ * return: true if no problems occures, false if failed to send
+ */
+int WNC14A2AInterface::sendIOTSms(const string& number, const string& message) 
+{
+
+    debugOutput(_debugUart,(char*)"+CALLED sendIOTSms(%s,%s)\n",number.c_str(), message.c_str());
+    _pwnc_mutex.lock();
+    int i =  _pwnc->sendSMSText((char*)number.c_str(), message.c_str());
+    _pwnc_mutex.unlock();
+
+    return i;
+}
+
+//
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//      NetworkStack API's that are not support in the WNC14A2A
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//
+
+int inline WNC14A2AInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) 
+{
+    debugOutput(_debugUart,(char*)"+CALLED socket_accept()\n");
+    _errors = NSAPI_ERROR_UNSUPPORTED;
+    return -1;
+}
+
+int inline WNC14A2AInterface::socket_bind(void *handle, const SocketAddress &address) 
+{
+    debugOutput(_debugUart,(char*)"+CALLED socket_bind()\n");
+    _errors = NSAPI_ERROR_UNSUPPORTED;
+    return -1;
+}
+
+
+int inline WNC14A2AInterface::socket_listen(void *handle, int backlog)
+{
+   debugOutput(_debugUart,(char*)"+CALLED socket_listen()\n");
+    _errors = NSAPI_ERROR_UNSUPPORTED;
+    return -1;
+}
+
--- a/WNC14A2AInterface.h	Mon Apr 17 23:59:13 2017 +0000
+++ b/WNC14A2AInterface.h	Tue Apr 18 00:05:54 2017 +0000
@@ -0,0 +1,332 @@
+/* WNC14A2A implementation of NetworkInterfaceAPI
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#ifndef WNC14A2A_INTERFACE_H
+#define WNC14A2A_INTERFACE_H
+
+#include <stdint.h>
+
+#include "mbed.h"
+#include "BufferedSerial.h"
+#include "WncControllerK64F/WncControllerK64F.h"
+
+#define WNC14A2A_SOCKET_COUNT 5
+
+
+typedef struct smsmsg_t {
+        string number;
+        string date;
+        string time;
+        string msg;
+    } IOTSMS;
+
+typedef struct socket_t {
+        int socket;             //index of this socket
+        string url;
+        SocketAddress addr;     //hold info for this socket
+        bool opened;            //has the socket been opened
+        int proto;              //this is a TCP or UDP socket
+    } WNCSOCKET;
+
+#define WNC_DEBUG   0           //1=enable the WNC startup debug output
+                                //0=disable the WNC startup debug output
+#define STOP_ON_FE  1           //1=hang forever if a fatal error occurs
+                                //0=simply return failed response for all socket calls
+#define DISPLAY_FE  1           //1 to display the fatal error when it occurs
+                                //0 to NOT display the fatal error
+#define RESETON_FE  0           //1 to cause the MCU to reset on fatal error
+                                //0 to NOT reset the MCU
+
+#define APN_DEFAULT             "m2m.com.attz"
+                        
+//
+// WNC Error Handling macros & data
+//
+#define FATAL_FLAG  WncController::WNC_NO_RESPONSE
+#define WNC_GOOD    WncController::WNC_ON
+
+#define RETfail return -1
+#define RETvoid return
+#define RETnull return NULL
+#define RETresume   
+
+#define DORET(x) RET##x
+
+#define TOSTR(x) #x
+#define INTSTR(x) TOSTR(x)
+#define FATAL_STR (char*)(__FILE__ ":" INTSTR(__LINE__))
+
+#if RESETON_FE == 1   //reset on fatal error
+#define MCURESET     ((*((volatile unsigned long *)0xE000ED0CU))=(unsigned long)((0x5fa<<16) | 0x04L))
+#define RSTMSG       "RESET MCU! "
+#else
+#define MCURESET
+#define RSTMSG       ""
+#endif
+
+#if DISPLAY_FE == 1  //display fatal error message
+#define PFE     {if(_debugUart)_debugUart->printf(RSTMSG "\r\n>>WNC FAILED @ %s\r\n", FATAL_STR);}
+#else
+#define PFE
+#endif
+
+#if STOP_ON_FE == 1  //halt cpu on fatal error
+#define FATAL_WNC_ERROR(v)  {_fatal_err_loc=FATAL_STR;PFE;MCURESET;while(1);}
+#else
+#define FATAL_WNC_ERROR(v)  {_fatal_err_loc=FATAL_STR;PFE;DORET(v);}
+#endif
+
+#define CHK_WNCFE(x,y)    if( x ){FATAL_WNC_ERROR(y);}
+
+#define MAX_SMS_MSGS    3
+
+using namespace WncController_fk;
+ 
+/** WNC14A2AInterface class
+ *  Implementation of the NetworkInterface for WNC14A2A 
+ */
+class WNC14A2AInterface : public NetworkStack, public CellularInterface
+{
+public:
+    /** WNC14A2AInterface Constructors...
+     * @param can include an APN string and/or a debug uart
+     */
+    WNC14A2AInterface(BufferedSerial *_dbgUart = NULL);
+    ~WNC14A2AInterface();
+
+    /** Set the cellular network APN and credentials
+     *
+     *  @param apn      Optional name of the network to connect to
+     *  @param user     Optional username for the APN
+     *  @param pass     Optional password fot the APN
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual nsapi_error_t set_credentials(const char *apn = 0,
+            const char *username = 0, const char *password = 0);
+ 
+    /** Start the interface
+     *
+     *  @param apn      Optional name of the network to connect to
+     *  @param username Optional username for your APN
+     *  @param password Optional password for your APN 
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual nsapi_error_t connect(const char *apn,
+            const char *username = 0, const char *password = 0);
+ 
+    /** Start the interface
+     *
+     *  Attempts to connect to a cellular network based on supplied credentials
+     *
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual nsapi_error_t connect();
+
+    /** Stop the interface
+     *
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual nsapi_error_t disconnect();
+ 
+    /** Get the internally stored IP address. From NetworkStack Class
+     *  @return             IP address of the interface or null if not yet connected
+     */
+    virtual const char *get_ip_address();
+ 
+    /** Get the network assigned IP address.
+     *  @return             IP address of the interface or null if not yet connected
+     */
+    const char *get_my_ip_address();
+
+    /** Get the internally stored MAC address.  From CellularInterface Class
+     *  @return             MAC address of the interface
+     */
+    virtual const char *get_mac_address();
+ 
+    /** Attach a function to be called when a text is recevieds
+     *  @param callback  function pointer to a callback that will accept the message 
+     *  contents when a text is received.
+     */
+    void sms_attach(void (*callback)(IOTSMS *));
+
+    void doDebug(int v);
+
+    bool registered();
+
+    void sms_start(void);
+
+    /** start listening for incomming SMS messages
+     *  @param time in msec to check
+     */
+    void sms_listen(uint16_t=1000);         // Configure device to listen for text messages 
+        
+    int getSMS(IOTSMS **msg);
+
+    int sendIOTSms(const string&, const string&);
+
+    char* getSMSnbr();
+
+
+protected:
+
+    /** Get Host IP by name. From NetworkStack Class
+     */
+    virtual nsapi_error_t gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version);
+
+
+    /** Provide access to the NetworkStack object
+     *
+     *  @return The underlying NetworkStack object
+     */
+    virtual NetworkStack *get_stack();
+
+    /** Open a socket. FROM NetworkStack
+     *  @param handle       Handle in which to store new socket
+     *  @param proto        Type of socket to open, NSAPI_TCP or NSAPI_UDP
+     *  @return             0 on success, negative on failure
+     */
+    virtual int socket_open(void **handle, nsapi_protocol_t proto);
+ 
+    /** Close the socket. FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @return             0 on success, negative on failure
+     *  @note On failure, any memory associated with the socket must still 
+     *        be cleaned up
+     */
+    virtual int socket_close(void *handle);
+ 
+    /** Bind a server socket to a specific port.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param address      Local address to listen for incoming connections on 
+     *  @return             0 on success, negative on failure.
+     */
+    virtual int socket_bind(void *handle, const SocketAddress &address);
+ 
+    /** Start listening for incoming connections.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param backlog      Number of pending connections that can be queued up at any
+     *                      one time [Default: 1]
+     *  @return             0 on success, negative on failure
+     */
+    virtual int socket_listen(void *handle, int backlog);
+ 
+    /** Connects this TCP socket to the server.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param address      SocketAddress to connect to
+     *  @return             0 on success, negative on failure
+     */
+    virtual int socket_connect(void *handle, const SocketAddress &address);
+ 
+    /** Accept a new connection.FROM NetworkStack
+     *  @param handle       Handle in which to store new socket
+     *  @param server       Socket handle to server to accept from
+     *  @return             0 on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_accept(nsapi_socket_t server,
+            nsapi_socket_t *handle, SocketAddress *address=0);
+ 
+    /** Send data to the remote host.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param data         The buffer to send to the host
+     *  @param size         The length of the buffer to send
+     *  @return             Number of written bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_send(void *handle, const void *data, unsigned size);
+ 
+    /** Receive data from the remote host.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param data         The buffer in which to store the data received from the host
+     *  @param size         The maximum length of the buffer
+     *  @return             Number of received bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_recv(void *handle, void *data, unsigned size);
+ 
+    /** Send a packet to a remote endpoint.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param address      The remote SocketAddress
+     *  @param data         The packet to be sent
+     *  @param size         The length of the packet to be sent
+     *  @return the         number of written bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
+ 
+    /** Receive a packet from a remote endpoint.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param address      Destination for the remote SocketAddress or null
+     *  @param buffer       The buffer for storing the incoming packet data
+     *                      If a packet is too long to fit in the supplied buffer,
+     *                      excess bytes are discarded
+     *  @param size         The length of the buffer
+     *  @return the         number of received bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
+ 
+    /** Register a callback on state change of the socket.FROM NetworkStack
+     *  @param handle       Socket handle
+     *  @param callback     Function to call on state change
+     *  @param data         Argument to pass to callback
+     *  @note Callback may be called in an interrupt context.
+     */
+    virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
+    
+    /** check for errors that may have occured
+     *  @param none.
+     *  @note this function can be called after any WNC14A2A class operation 
+     *        to determine error specifics if desired.
+     */
+    uint16_t wnc14a2a_chk_error(void) { return _errors; }
+
+
+private:
+    // WncController Class for managing the 14A2a
+    friend class WncControllerK64F;  
+
+    bool m_wncpoweredup;                    //track if WNC has been power-up
+    bool m_debug;
+
+    WncIpStats myNetStats;                  //maintaint the network statistics
+    WncControllerK64F_fk::WncControllerK64F *_pwnc; //pointer to the WncController instance
+
+    int m_active_socket;                    // a 'pseudo' global to track the active socket
+    BufferedSerial *_debugUart;                     // Serial object for parser to communicate with radio
+    char *_fatal_err_loc;                   // holds string containing location of fatal error
+    nsapi_error_t _errors;
+
+    bool m_smsmoning;                       // Track if the SMS monitoring thread is running
+    EventQueue sms_queue;                   // Queue used to schedule for SMS checks
+    Semaphore sms_rx_sem;                   // Semaphore to signal sms_event_thread to check for incoming text 
+    void (*_sms_cb)(IOTSMS *);              // Callback when text message is received. User must define this as 
+                                            // a static function because I'm not handling an object offset
+    IOTSMS m_MsgText, m_MsgText_array[MAX_SMS_MSGS];       // Used to pass SMS message to the user
+    struct WncController::WncSmsList m_smsmsgs;            //use the WncSmsList structure to hold messages
+
+    void handle_sms_event();                // Handle incoming text data
+
+    char _mac_address[NSAPI_MAC_SIZE];      // local Mac
+    void debugOutput(BufferedSerial *dbgOut, char * format, ...);
+};
+
+#endif