Port of TI's CC3100 Websock camera demo. Using FreeRTOS, mbedTLS, also parts of Arducam for cams ov5642 and 0v2640. Can also use MT9D111. Work in progress. Be warned some parts maybe a bit flacky. This is for Seeed Arch max only, for an M3, see the demo for CM3 using the 0v5642 aducam mini.

Dependencies:   mbed

simplelink/cc3100_driver.cpp

Committer:
dflet
Date:
2015-09-15
Revision:
22:f9b5e0b80bf2
Parent:
19:3dd3e7f30f8b

File content as of revision 22:f9b5e0b80bf2:

/*
* driver.c - CC31xx/CC32xx Host Driver Implementation
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
*
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*    Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the
*    distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "cc3100_simplelink.h"
#include "cc3100_protocol.h"
#include "cc3100_driver.h"

#include "fPtr_func.h"
#include "cli_uart.h"

#if (defined (SL_PLATFORM_MULTI_THREADED)) || (defined (SL_PLATFORM_EXTERNAL_SPAWN))
#include "osi.h"
#endif

/*****************************************************************************/
/* Macro declarations                                                        */
/*****************************************************************************/

namespace mbed_cc3100 {

#ifndef SL_MEMORY_MGMT_DYNAMIC
typedef struct {
    uint32_t      Align;
    _SlDriverCb_t DriverCB;
    uint8_t AsyncRespBuf[SL_ASYNC_MAX_MSG_LEN];
} _SlStatMem_t;

_SlStatMem_t g_StatMem;
#endif


_SlDriverCb_t* g_pCB = NULL;

uint8_t gFirstCmdMode = 0;

const _SlSyncPattern_t g_H2NSyncPattern = H2N_SYNC_PATTERN;
const _SlSyncPattern_t g_H2NCnysPattern = H2N_CNYS_PATTERN;
volatile uint8_t RxIrqCnt;

#ifndef SL_TINY_EXT
const _SlActionLookup_t _SlActionLookupTable[] = {
    {ACCEPT_ID, SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE, (_SlSpawnEntryFunc_t) &_sl_HandleAsync_Accept},
    {CONNECT_ID, SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE,(_SlSpawnEntryFunc_t) &_sl_HandleAsync_Connect},
    {SELECT_ID, SL_OPCODE_SOCKET_SELECTASYNCRESPONSE,(_SlSpawnEntryFunc_t) &_sl_HandleAsync_Select},
    {GETHOSYBYNAME_ID, SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE,(_SlSpawnEntryFunc_t) &_sl_HandleAsync_DnsGetHostByName},
    {GETHOSYBYSERVICE_ID, SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICEASYNCRESPONSE,(_SlSpawnEntryFunc_t) &_sl_HandleAsync_DnsGetHostByService},
    {PING_ID, SL_OPCODE_NETAPP_PINGREPORTREQUESTRESPONSE, (_SlSpawnEntryFunc_t) &_sl_HandleAsync_PingResponse},
    {START_STOP_ID, SL_OPCODE_DEVICE_STOP_ASYNC_RESPONSE,(_SlSpawnEntryFunc_t) &_sl_HandleAsync_Stop}

};
#else
const _SlActionLookup_t _SlActionLookupTable[] = 
{
    {CONNECT_ID, SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Connect},
    {GETHOSYBYNAME_ID, SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_DnsGetHostByName},  
    {START_STOP_ID, SL_OPCODE_DEVICE_STOP_ASYNC_RESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Stop}
};
#endif

typedef struct
{
    uint16_t opcode;
    uint8_t  event;
} OpcodeKeyVal_t;

/* The table translates opcode to user's event type */
const OpcodeKeyVal_t OpcodeTranslateTable[] = 
{
{SL_OPCODE_WLAN_SMART_CONFIG_START_ASYNC_RESPONSE, SL_WLAN_SMART_CONFIG_COMPLETE_EVENT},
{SL_OPCODE_WLAN_SMART_CONFIG_STOP_ASYNC_RESPONSE,SL_WLAN_SMART_CONFIG_STOP_EVENT},
{SL_OPCODE_WLAN_STA_CONNECTED, SL_WLAN_STA_CONNECTED_EVENT},
{SL_OPCODE_WLAN_STA_DISCONNECTED,SL_WLAN_STA_DISCONNECTED_EVENT},
{SL_OPCODE_WLAN_P2P_DEV_FOUND,SL_WLAN_P2P_DEV_FOUND_EVENT},    
{SL_OPCODE_WLAN_P2P_NEG_REQ_RECEIVED, SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT},
{SL_OPCODE_WLAN_CONNECTION_FAILED, SL_WLAN_CONNECTION_FAILED_EVENT},
{SL_OPCODE_WLAN_WLANASYNCCONNECTEDRESPONSE, SL_WLAN_CONNECT_EVENT},
{SL_OPCODE_WLAN_WLANASYNCDISCONNECTEDRESPONSE, SL_WLAN_DISCONNECT_EVENT},
{SL_OPCODE_NETAPP_IPACQUIRED, SL_NETAPP_IPV4_IPACQUIRED_EVENT},
{SL_OPCODE_NETAPP_IPACQUIRED_V6, SL_NETAPP_IPV6_IPACQUIRED_EVENT},
{SL_OPCODE_NETAPP_IP_LEASED, SL_NETAPP_IP_LEASED_EVENT},
{SL_OPCODE_NETAPP_IP_RELEASED, SL_NETAPP_IP_RELEASED_EVENT},
{SL_OPCODE_SOCKET_TXFAILEDASYNCRESPONSE, SL_SOCKET_TX_FAILED_EVENT},
{SL_OPCODE_SOCKET_SOCKETASYNCEVENT, SL_SOCKET_ASYNC_EVENT}
};

/*

#define SL_OPCODE_SILO_DEVICE                           ( 0x0 << SL_OPCODE_SILO_OFFSET )
#define SL_OPCODE_SILO_WLAN                             ( 0x1 << SL_OPCODE_SILO_OFFSET )
#define SL_OPCODE_SILO_SOCKET                           ( 0x2 << SL_OPCODE_SILO_OFFSET )
#define SL_OPCODE_SILO_NETAPP                           ( 0x3 << SL_OPCODE_SILO_OFFSET )
#define SL_OPCODE_SILO_NVMEM                            ( 0x4 << SL_OPCODE_SILO_OFFSET )
#define SL_OPCODE_SILO_NETCFG                           ( 0x5 << SL_OPCODE_SILO_OFFSET )


*/

/* The Lookup table below holds the event handlers to be called according to the incoming
    RX message SILO type */
const _SlSpawnEntryFunc_t RxMsgClassLUT[] = {
    (_SlSpawnEntryFunc_t)_SlDrvDeviceEventHandler, /* SL_OPCODE_SILO_DEVICE */
#if defined(sl_WlanEvtHdlr) || defined(EXT_LIB_REGISTERED_WLAN_EVENTS)
    (_SlSpawnEntryFunc_t)_SlDrvHandleWlanEvents,           /* SL_OPCODE_SILO_WLAN */
#else
    NULL,
#endif
#if defined (sl_SockEvtHdlr) || defined(EXT_LIB_REGISTERED_SOCK_EVENTS)
    (_SlSpawnEntryFunc_t)_SlDrvHandleSockEvents,   /* SL_OPCODE_SILO_SOCKET */
#else
    NULL,
#endif

#if defined(sl_NetAppEvtHdlr) || defined(EXT_LIB_REGISTERED_NETAPP_EVENTS)
    (_SlSpawnEntryFunc_t)_SlDrvHandleNetAppEvents, /* SL_OPCODE_SILO_NETAPP */
#else
    NULL,  
#endif
    NULL,                                          /* SL_OPCODE_SILO_NVMEM */
    NULL,                                          /* SL_OPCODE_SILO_NETCFG */
    NULL,
    NULL
};

//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))
cc3100_driver::cc3100_driver(cc3100_spi &spi, cc3100_nonos &nonos, cc3100_netapp &netapp, cc3100_flowcont &flowcont)
    :  _spi(spi), _nonos(nonos), _netapp(netapp), _flowcont(flowcont)
{
}
#else

cc3100_driver::cc3100_driver(cc3100_spi &spi, cc3100_netapp &netapp, cc3100_flowcont &flowcont)
    :  _spi(spi), _netapp(netapp), _flowcont(flowcont)
{
}
#endif

cc3100_driver::~cc3100_driver()
{

}

/*****************************************************************************/
/* Variables                                                                 */
/*****************************************************************************/

/********************************************************************************/

uint8_t cc3100_driver::_SlDrvProtectAsyncRespSetting(uint8_t *pAsyncRsp, uint8_t ActionID, uint8_t SocketID)
{
    uint8_t ObjIdx;


    /* Use Obj to issue the command, if not available try later */
    ObjIdx = _SlDrvWaitForPoolObj(ActionID, SocketID);

    if (MAX_CONCURRENT_ACTIONS != ObjIdx)
    {
        _SlDrvProtectionObjLockWaitForever();
        g_pCB->ObjPool[ObjIdx].pRespArgs = pAsyncRsp;
        _SlDrvProtectionObjUnLock();
    }

    return ObjIdx;
}


/*****************************************************************************/
/* Internal functions                                                        */
/*****************************************************************************/
bool cc3100_driver::_SL_PENDING_RX_MSG(pDriver* pDriverCB){
	
	if(RxIrqCnt != (pDriverCB)->RxDoneCnt){
	    return TRUE;
 	}else{
	    return FALSE;
	}
}

/*****************************************************************************
_SlDrvDriverCBInit - init Driver Control Block
*****************************************************************************/
void cc3100_driver::_SlDrvDriverCBInit(void)
{
    
    uint8_t Idx = 0;

#ifdef SL_MEMORY_MGMT_DYNAMIC

    g_pCB = sl_Malloc(sizeof(_SlDriverCb_t));
#else
    g_pCB = &(g_StatMem.DriverCB);
#endif
   
    MALLOC_OK_CHECK(g_pCB);
    _SlDrvMemZero(g_pCB, sizeof(_SlDriverCb_t));
    RxIrqCnt = 0;
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))
    OSI_RET_OK_CHECK( _nonos.sl_SyncObjCreate(&g_pCB->CmdSyncObj, "CmdSyncObj") );
    _nonos.sl_SyncObjClear(&g_pCB->CmdSyncObj);
    OSI_RET_OK_CHECK( _nonos.sl_LockObjCreate(&g_pCB->GlobalLockObj, "GlobalLockObj") );
    OSI_RET_OK_CHECK( _nonos.sl_LockObjCreate(&g_pCB->ProtectionLockObj, "ProtectionLockObj") );
#else    
    OSI_RET_OK_CHECK( sl_SyncObjCreate(&g_pCB->CmdSyncObj, "CmdSyncObj") );
    sl_SyncObjClear(&g_pCB->CmdSyncObj);
    OSI_RET_OK_CHECK( sl_LockObjCreate(&g_pCB->GlobalLockObj, "GlobalLockObj") );
    OSI_RET_OK_CHECK( sl_LockObjCreate(&g_pCB->ProtectionLockObj, "ProtectionLockObj") );
#endif    
    /* Init Drv object */
    _SlDrvMemZero(&g_pCB->ObjPool[0], MAX_CONCURRENT_ACTIONS*sizeof(_SlPoolObj_t));

    /* place all Obj in the free list*/
    g_pCB->FreePoolIdx = 0;

    for (Idx = 0 ; Idx < MAX_CONCURRENT_ACTIONS ; Idx++)
    {
        g_pCB->ObjPool[Idx].NextIndex = Idx + 1;
        g_pCB->ObjPool[Idx].AdditionalData = SL_MAX_SOCKETS;
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))
        OSI_RET_OK_CHECK( _nonos.sl_SyncObjCreate(&g_pCB->ObjPool[Idx].SyncObj, "SyncObj"));
        _nonos.sl_SyncObjClear(&g_pCB->ObjPool[Idx].SyncObj);
#else
        OSI_RET_OK_CHECK( sl_SyncObjCreate(&g_pCB->ObjPool[Idx].SyncObj, "SyncObj"));
        sl_SyncObjClear(&g_pCB->ObjPool[Idx].SyncObj);
#endif               
    }

     g_pCB->ActivePoolIdx = MAX_CONCURRENT_ACTIONS;
     g_pCB->PendingPoolIdx = MAX_CONCURRENT_ACTIONS;

    /* Flow control init */
    g_pCB->FlowContCB.TxPoolCnt = FLOW_CONT_MIN;
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))   
    OSI_RET_OK_CHECK(_nonos.sl_LockObjCreate(&g_pCB->FlowContCB.TxLockObj, "TxLockObj"));
    OSI_RET_OK_CHECK(_nonos.sl_SyncObjCreate(&g_pCB->FlowContCB.TxSyncObj, "TxSyncObj"));
#else
    OSI_RET_OK_CHECK(sl_LockObjCreate(&g_pCB->FlowContCB.TxLockObj, "TxLockObj"));
    OSI_RET_OK_CHECK(sl_SyncObjCreate(&g_pCB->FlowContCB.TxSyncObj, "TxSyncObj"));
#endif  
    gFirstCmdMode = 0;  
}

/*****************************************************************************
_SlDrvDriverCBDeinit - De init Driver Control Block
*****************************************************************************/
void cc3100_driver::_SlDrvDriverCBDeinit()
{
    uint8_t        Idx = 0;
    
    /* Flow control de-init */
    g_pCB->FlowContCB.TxPoolCnt = 0;
//#ifndef SL_PLATFORM_MULTI_THREADED 
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))   
    OSI_RET_OK_CHECK(_nonos.sl_LockObjDelete(&g_pCB->FlowContCB.TxLockObj));
    OSI_RET_OK_CHECK(_nonos.sl_SyncObjDelete(&g_pCB->FlowContCB.TxSyncObj));
    
    OSI_RET_OK_CHECK( _nonos.sl_SyncObjDelete(&g_pCB->CmdSyncObj) );
    OSI_RET_OK_CHECK( _nonos.sl_LockObjDelete(&g_pCB->GlobalLockObj) );
    OSI_RET_OK_CHECK( _nonos.sl_LockObjDelete(&g_pCB->ProtectionLockObj) );
#else    
    OSI_RET_OK_CHECK(sl_LockObjDelete(&g_pCB->FlowContCB.TxLockObj));
    OSI_RET_OK_CHECK(sl_SyncObjDelete(&g_pCB->FlowContCB.TxSyncObj));
    
    OSI_RET_OK_CHECK( sl_SyncObjDelete(&g_pCB->CmdSyncObj) );
    OSI_RET_OK_CHECK( sl_LockObjDelete(&g_pCB->GlobalLockObj) );
    OSI_RET_OK_CHECK( sl_LockObjDelete(&g_pCB->ProtectionLockObj) );   
#endif
    
#ifndef SL_TINY_EXT
    for (Idx = 0; Idx < MAX_CONCURRENT_ACTIONS; Idx++)
#endif

    g_pCB->FreePoolIdx = 0;
    g_pCB->PendingPoolIdx = MAX_CONCURRENT_ACTIONS;
    g_pCB->ActivePoolIdx = MAX_CONCURRENT_ACTIONS;

#ifdef SL_MEMORY_MGMT_DYNAMIC
    sl_Free(g_pCB);
#else
    g_pCB = NULL;
#endif

    g_pCB = NULL;
}

/*****************************************************************************
_SlDrvRxIrqHandler - Interrupt handler
*****************************************************************************/

void cc3100_driver::_SlDrvRxIrqHandler(void *pValue)
{
    
    int32_t rv = 0;
    _spi.MaskIntHdlr();
    
    RxIrqCnt++;
    
    if (TRUE == g_pCB->IsCmdRespWaited) {
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))      
        OSI_RET_OK_CHECK( _nonos.sl_SyncObjSignalFromIRQ(&g_pCB->CmdSyncObj) );
#else        
        OSI_RET_OK_CHECK( sl_SyncObjSignalFromIRQ(&g_pCB->CmdSyncObj) );
#endif       
    } else {
#if (defined (SL_PLATFORM_MULTI_THREADED)) || (defined (SL_PLATFORM_EXTERNAL_SPAWN))               
        rv = sl_Spawn((_SlSpawnEntryFunc_t)_SlDrvMsgReadSpawnCtx, NULL, 0);

        if(rv <0){
           Uart_Write((uint8_t*)"\n\r OSI_OPERATION_FAILED \n\r");
        }   
#else        
        _nonos._SlNonOsSpawn((_SlSpawnEntryFunc_t)&_SlDrvMsgReadSpawnCtx, NULL, 0);
#endif    	
//#ifndef SL_PLATFORM_MULTI_THREADED        
//        _nonos._SlNonOsSpawn((_SlSpawnEntryFunc_t)&_SlDrvMsgReadSpawnCtx, NULL, 0);
//#else
//        sl_Spawn((_SlSpawnEntryFunc_t)&_SlDrvMsgReadSpawnCtx, NULL, 0);
//#endif        
    }
}

/*****************************************************************************
_SlDrvCmdOp
*****************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvCmdOp(_SlCmdCtrl_t *pCmdCtrl,void* pTxRxDescBuff, _SlCmdExt_t *pCmdExt)
{
    _SlReturnVal_t RetVal;
    
    _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj);
    g_pCB->IsCmdRespWaited = TRUE;
    SL_TRACE0(DBG_MSG, MSG_312, "_SlDrvCmdOp: call _SlDrvMsgWrite");
    
    /* send the message */
    RetVal = _SlDrvMsgWrite(pCmdCtrl, pCmdExt, (uint8_t*)pTxRxDescBuff);
    
    if(SL_OS_RET_CODE_OK == RetVal) {

#ifndef SL_IF_TYPE_UART
        /* Waiting for SPI to stabilize after first command */
        if( 0 == gFirstCmdMode ) {           
            gFirstCmdMode = 1;
            wait_ms(2);
        }
#endif
        
        /* wait for respond */
        RetVal = _SlDrvMsgReadCmdCtx(); /* will free global lock */
        SL_TRACE0(DBG_MSG, MSG_314, "_SlDrvCmdOp: exited _SlDrvMsgReadCmdCtx");
    } else 
    {
        _SlDrvObjUnLock(&g_pCB->GlobalLockObj);
    }
    return RetVal;
}

/*****************************************************************************
_SlDrvDataReadOp
*****************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvDataReadOp(_SlSd_t Sd, _SlCmdCtrl_t *pCmdCtrl, void* pTxRxDescBuff, _SlCmdExt_t *pCmdExt)
{
    _SlReturnVal_t RetVal;
    uint8_t ObjIdx = MAX_CONCURRENT_ACTIONS;
    _SlArgsData_t pArgsData;

    /* Validate input arguments */
    VERIFY_PROTOCOL(NULL != pCmdExt->pRxPayload);

    /* If zero bytes is requested, return error. */
    /*  This allows us not to fill remote socket's IP address in return arguments */
    VERIFY_PROTOCOL(0 != pCmdExt->RxPayloadLen);

    /* Validate socket */
    if((Sd & BSD_SOCKET_ID_MASK) >= SL_MAX_SOCKETS) {
        return SL_EBADF;
    }

    /*Use Obj to issue the command, if not available try later*/
    ObjIdx = (uint8_t)_SlDrvWaitForPoolObj(RECV_ID, Sd & BSD_SOCKET_ID_MASK);

    if (MAX_CONCURRENT_ACTIONS == ObjIdx) {
        return SL_POOL_IS_EMPTY;
    }
    
    _SlDrvProtectionObjLockWaitForever();
    
    pArgsData.pData = pCmdExt->pRxPayload;
    pArgsData.pArgs =  (uint8_t *)pTxRxDescBuff;
    g_pCB->ObjPool[ObjIdx].pRespArgs =  (uint8_t *)&pArgsData;
    _SlDrvProtectionObjUnLock();

    /* Do Flow Control check/update for DataWrite operation */
    _SlDrvObjLockWaitForever(&g_pCB->FlowContCB.TxLockObj);
    
    /* Clear SyncObj for the case it was signalled before TxPoolCnt */
    /* dropped below '1' (last Data buffer was taken)  */
    /* OSI_RET_OK_CHECK( sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj) ); */
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))       
    _nonos.sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj);
#else    
    sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj);
#endif
    if(g_pCB->FlowContCB.TxPoolCnt <= FLOW_CONT_MIN) {

        /* If TxPoolCnt was increased by other thread at this moment,
        TxSyncObj won't wait here */
    _SlDrvSyncObjWaitForever(&g_pCB->FlowContCB.TxSyncObj);
       
    }

    _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj);

    VERIFY_PROTOCOL(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN);
    g_pCB->FlowContCB.TxPoolCnt--;

    _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj);

    /* send the message */
    RetVal =  _SlDrvMsgWrite(pCmdCtrl, pCmdExt, (uint8_t *)pTxRxDescBuff);

    _SlDrvObjUnLock(&g_pCB->GlobalLockObj);

    if(SL_OS_RET_CODE_OK == RetVal) {
        /* Wait for response message. Will be signaled by _SlDrvMsgRead. */
        _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj);
    }

    _SlDrvReleasePoolObj(ObjIdx);
    return RetVal;
}

/* ******************************************************************************/
/*   _SlDrvDataWriteOp                                                          */
/* ******************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvDataWriteOp(_SlSd_t Sd, _SlCmdCtrl_t *pCmdCtrl, void* pTxRxDescBuff, _SlCmdExt_t *pCmdExt)
{
    _SlReturnVal_t  RetVal = SL_EAGAIN; /*  initiated as SL_EAGAIN for the non blocking mode */
    while( 1 ) {
        /*  Do Flow Control check/update for DataWrite operation */        
        _SlDrvObjLockWaitForever(&g_pCB->FlowContCB.TxLockObj);

        /*  Clear SyncObj for the case it was signalled before TxPoolCnt */
        /*  dropped below '1' (last Data buffer was taken) */
        /* OSI_RET_OK_CHECK( sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj) ); */
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))               
        _nonos.sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj);
#else        
        sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj);
#endif               
        /*  we have indication that the last send has failed - socket is no longer valid for operations  */
        if(g_pCB->SocketTXFailure & (1<<(Sd & BSD_SOCKET_ID_MASK))) {
            _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj);
            return SL_SOC_ERROR;
        }
        
        if(g_pCB->FlowContCB.TxPoolCnt <= FLOW_CONT_MIN + 1) {
            /*  we have indication that this socket is set as blocking and we try to  */
            /*  unblock it - return an error */
            if( g_pCB->SocketNonBlocking & (1<< (Sd & BSD_SOCKET_ID_MASK)))
            {
            _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj);
                return RetVal;
            }
            /*  If TxPoolCnt was increased by other thread at this moment, */
            /*  TxSyncObj won't wait here */
            _SlDrvSyncObjWaitForever(&g_pCB->FlowContCB.TxSyncObj);
        }

        if(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN + 1 ) {
            break;
        } 
        else 
        {
        _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj);
        }
    }

    _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj);


    VERIFY_PROTOCOL(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN + 1 );
    g_pCB->FlowContCB.TxPoolCnt--;

    _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj);

    /* send the message */
    RetVal =  _SlDrvMsgWrite(pCmdCtrl, pCmdExt, (uint8_t*)pTxRxDescBuff);
    
    _SlDrvObjUnLock(&g_pCB->GlobalLockObj);

    return RetVal;
}

/* ******************************************************************************/
/*  _SlDrvMsgWrite */
/* ******************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvMsgWrite(_SlCmdCtrl_t  *pCmdCtrl, _SlCmdExt_t  *pCmdExt, uint8_t *pTxRxDescBuff)
{
    //printf("_SlDrvMsgWrite\r\n");
    uint8_t sendRxPayload = FALSE;
    VERIFY_PROTOCOL(NULL != pCmdCtrl);

    g_pCB->FunctionParams.pCmdCtrl = pCmdCtrl;
    g_pCB->FunctionParams.pTxRxDescBuff = pTxRxDescBuff;
    g_pCB->FunctionParams.pCmdExt = pCmdExt;
    
    g_pCB->TempProtocolHeader.Opcode   = pCmdCtrl->Opcode;
    g_pCB->TempProtocolHeader.Len   = _SL_PROTOCOL_CALC_LEN(pCmdCtrl, pCmdExt);

    if (pCmdExt && pCmdExt->RxPayloadLen < 0 && pCmdExt->TxPayloadLen)
    {
        pCmdExt->RxPayloadLen = pCmdExt->RxPayloadLen * (-1); /* change sign */
        sendRxPayload = TRUE;
        g_pCB->TempProtocolHeader.Len = g_pCB->TempProtocolHeader.Len + pCmdExt->RxPayloadLen;
    }
    
#ifdef SL_START_WRITE_STAT
    sl_IfStartWriteSequence(g_pCB->FD);
#endif

#ifdef SL_IF_TYPE_UART
    /*  Write long sync pattern */
    NWP_IF_WRITE_CHECK(g_pCB->FD, (uint8_t *)&g_H2NSyncPattern.Long, 2*SYNC_PATTERN_LEN);
#else
    /*  Write short sync pattern */
    NWP_IF_WRITE_CHECK(g_pCB->FD, (uint8_t *)&g_H2NSyncPattern.Short, SYNC_PATTERN_LEN);
#endif
    /*  Header */
    NWP_IF_WRITE_CHECK(g_pCB->FD, (uint8_t *)&g_pCB->TempProtocolHeader, _SL_CMD_HDR_SIZE);

    /*  Descriptors */
    if (pTxRxDescBuff && pCmdCtrl->TxDescLen > 0)
    {
    	NWP_IF_WRITE_CHECK(g_pCB->FD, pTxRxDescBuff, 
                           _SL_PROTOCOL_ALIGN_SIZE(pCmdCtrl->TxDescLen));
    }

    /*  A special mode where Rx payload and Rx length are used as Tx as well */
    /*  This mode requires no Rx payload on the response and currently used by fs_Close and sl_Send on */
    /*  transceiver mode */
    if (sendRxPayload == TRUE )
    {
     	NWP_IF_WRITE_CHECK(g_pCB->FD, pCmdExt->pRxPayload, _SL_PROTOCOL_ALIGN_SIZE(pCmdExt->RxPayloadLen));
    }

    /*  Payload */
    if (pCmdExt && pCmdExt->TxPayloadLen > 0)
    {
        /*  If the message has payload, it is mandatory that the message's arguments are protocol aligned. */
        /*  Otherwise the aligning of arguments will create a gap between arguments and payload. */
        VERIFY_PROTOCOL(_SL_IS_PROTOCOL_ALIGNED_SIZE(pCmdCtrl->TxDescLen));

    	NWP_IF_WRITE_CHECK(g_pCB->FD, pCmdExt->pTxPayload, _SL_PROTOCOL_ALIGN_SIZE(pCmdExt->TxPayloadLen));
    }

    _SL_DBG_CNT_INC(MsgCnt.Write);

#ifdef SL_START_WRITE_STAT
    sl_IfEndWriteSequence(g_pCB->FD);
#endif

    return SL_OS_RET_CODE_OK;
}

/* ******************************************************************************/
/*  _SlDrvMsgRead  */
/* ******************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvMsgRead(void)
{
    /*  alignment for small memory models */
    union {
      uint8_t             TempBuf[_SL_RESP_HDR_SIZE];
      uint32_t            DummyBuf[2];
    } uBuf;
    uint8_t               TailBuffer[4];
    uint16_t              LengthToCopy;
    uint16_t              AlignedLengthRecv;
    uint8_t               AlignSize;
    uint8_t               *pAsyncBuf = NULL;
    uint16_t              OpCode;
    uint16_t              RespPayloadLen;
    uint8_t               sd = SL_MAX_SOCKETS;
    _SlRxMsgClass_e   RxMsgClass;
    

    /* save params in global CB */
    g_pCB->FunctionParams.AsyncExt.pAsyncBuf      = NULL;
    g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler= NULL;

    
    VERIFY_RET_OK(_SlDrvRxHdrRead((uint8_t*)(uBuf.TempBuf), &AlignSize));
    OpCode = OPCODE(uBuf.TempBuf);
    RespPayloadLen = RSP_PAYLOAD_LEN(uBuf.TempBuf);


    /* 'Init Compelete' message bears no valid FlowControl info */
    if(SL_OPCODE_DEVICE_INITCOMPLETE != OpCode) {
        g_pCB->FlowContCB.TxPoolCnt = ((_SlResponseHeader_t *)uBuf.TempBuf)->TxPoolCnt;
        g_pCB->SocketNonBlocking = ((_SlResponseHeader_t *)uBuf.TempBuf)->SocketNonBlocking;
        g_pCB->SocketTXFailure = ((_SlResponseHeader_t *)uBuf.TempBuf)->SocketTXFailure;

        if(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN) {
            _SlDrvSyncObjSignal(&g_pCB->FlowContCB.TxSyncObj);
        }
    }
   
    /* Find the RX messaage class and set its async event handler */
    _SlDrvClassifyRxMsg(OpCode);
    RxMsgClass = g_pCB->FunctionParams.AsyncExt.RxMsgClass;


    switch(RxMsgClass)
    {
    case ASYNC_EVT_CLASS:

            VERIFY_PROTOCOL(NULL == pAsyncBuf);

#ifdef SL_MEMORY_MGMT_DYNAMIC
        g_pCB->FunctionParams.AsyncExt.pAsyncBuf = sl_Malloc(SL_ASYNC_MAX_MSG_LEN);
#else
        g_pCB->FunctionParams.AsyncExt.pAsyncBuf = g_StatMem.AsyncRespBuf;
#endif
            /* set the local pointer to the allocated one */
            pAsyncBuf = g_pCB->FunctionParams.AsyncExt.pAsyncBuf;

            /* clear the async buffer */
            _SlDrvMemZero(pAsyncBuf, SL_ASYNC_MAX_MSG_LEN);
            
            MALLOC_OK_CHECK(pAsyncBuf);

            memcpy(pAsyncBuf, uBuf.TempBuf, _SL_RESP_HDR_SIZE);
			if (_SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen) <= SL_ASYNC_MAX_PAYLOAD_LEN)
			{
				AlignedLengthRecv = _SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen);
			}
			else
			{
				AlignedLengthRecv = _SL_PROTOCOL_ALIGN_SIZE(SL_ASYNC_MAX_PAYLOAD_LEN);
			}
            if (RespPayloadLen > 0)
            {
                NWP_IF_READ_CHECK(g_pCB->FD, pAsyncBuf + _SL_RESP_HDR_SIZE, AlignedLengthRecv);
            }
        /* In case ASYNC RX buffer length is smaller then the received data length, dump the rest */
			if ((_SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen) > SL_ASYNC_MAX_PAYLOAD_LEN))
            {
				AlignedLengthRecv = _SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen) - SL_ASYNC_MAX_PAYLOAD_LEN;
                while (AlignedLengthRecv > 0)
                {
                NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer,4);
                AlignedLengthRecv = AlignedLengthRecv - 4;
                }
            }
            
            _SlDrvProtectionObjLockWaitForever();
          
			if (
#ifndef SL_TINY_EXT               
                (SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE == OpCode) || (SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE_V6 == OpCode) || 
#endif                
                (SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE == OpCode)
               )
			{
				/* go over the active list if exist to find obj waiting for this Async event */
				sd = ((((_SocketResponse_t *)(pAsyncBuf + _SL_RESP_HDR_SIZE))->sd) & BSD_SOCKET_ID_MASK);
			}
			_SlFindAndSetActiveObj(OpCode, sd);
            _SlDrvProtectionObjUnLock();

            break;
    case RECV_RESP_CLASS:
        {
            uint8_t ExpArgSize; /*  Expected size of Recv/Recvfrom arguments */

            switch(OpCode)
            {
            case SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE:
                ExpArgSize = RECVFROM_IPV4_ARGS_SIZE;
                break;
#ifndef SL_TINY_EXT                        
            case SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6:
                ExpArgSize = RECVFROM_IPV6_ARGS_SIZE;
                break;
#endif                        
            default:
                /* SL_OPCODE_SOCKET_RECVASYNCRESPONSE: */
                ExpArgSize = RECV_ARGS_SIZE;
            }              

            /*  Read first 4 bytes of Recv/Recvfrom response to get SocketId and actual  */
            /*  response data length */
            NWP_IF_READ_CHECK(g_pCB->FD, &uBuf.TempBuf[4], RECV_ARGS_SIZE);

            /*  Validate Socket ID and Received Length value.  */
            VERIFY_PROTOCOL((SD(&uBuf.TempBuf[4])& BSD_SOCKET_ID_MASK) < SL_MAX_SOCKETS);

            _SlDrvProtectionObjLockWaitForever();

            /* go over the active list if exist to find obj waiting for this Async event */
				VERIFY_RET_OK(_SlFindAndSetActiveObj(OpCode,SD(&uBuf.TempBuf[4]) & BSD_SOCKET_ID_MASK));

            /*  Verify data is waited on this socket. The pArgs should have been set by _SlDrvDataReadOp(). */
            VERIFY_SOCKET_CB(NULL !=  ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pData))->pArgs);	

            memcpy( ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pArgs, &uBuf.TempBuf[4], RECV_ARGS_SIZE);

            if(ExpArgSize > RECV_ARGS_SIZE)
            {
                NWP_IF_READ_CHECK(g_pCB->FD,
                    ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pArgs + RECV_ARGS_SIZE,
                    ExpArgSize - RECV_ARGS_SIZE);
            }

            /*  Here g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pData contains requested(expected) Recv/Recvfrom DataSize. */
            /*  Overwrite requested DataSize with actual one. */
            /*  If error is received, this information will be read from arguments. */
            if(ACT_DATA_SIZE(&uBuf.TempBuf[4]) > 0)
            {       
                VERIFY_SOCKET_CB(NULL != ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pData);

                /*  Read 4 bytes aligned from interface */
                /*  therefore check the requested length and read only  */
                /*  4 bytes aligned data. The rest unaligned (if any) will be read */
                /*  and copied to a TailBuffer  */
                LengthToCopy = ACT_DATA_SIZE(&uBuf.TempBuf[4]) & (3);
                AlignedLengthRecv = ACT_DATA_SIZE(&uBuf.TempBuf[4]) & (~3);
                if( AlignedLengthRecv >= 4)
                {
                    NWP_IF_READ_CHECK(g_pCB->FD,((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pData,AlignedLengthRecv );                      
                }
                /*  copy the unaligned part, if any */
                if( LengthToCopy > 0) 
                {
                    NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer,4);
                    /*  copy TailBuffer unaligned part (1/2/3 bytes) */
                    memcpy(((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pData + AlignedLengthRecv,TailBuffer,LengthToCopy);                    
                }                  
            }
                 _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj);
                 _SlDrvProtectionObjUnLock();
        }
        break;

        case CMD_RESP_CLASS:

            /*  Some commands pass a maximum arguments size. */
            /*  In this case Driver will send extra dummy patterns to NWP if */
            /*  the response message is smaller than maximum. */
            /*  When RxDescLen is not exact, using RxPayloadLen is forbidden! */
            /*  If such case cannot be avoided - parse message here to detect */
            /*  arguments/payload border. */
            NWP_IF_READ_CHECK(g_pCB->FD, g_pCB->FunctionParams.pTxRxDescBuff, _SL_PROTOCOL_ALIGN_SIZE(g_pCB->FunctionParams.pCmdCtrl->RxDescLen));

            if((NULL != g_pCB->FunctionParams.pCmdExt) && (0 != g_pCB->FunctionParams.pCmdExt->RxPayloadLen)) {
                /*  Actual size of command's response payload: <msg_payload_len> - <rsp_args_len> */
                int16_t    ActDataSize = RSP_PAYLOAD_LEN(uBuf.TempBuf) - g_pCB->FunctionParams.pCmdCtrl->RxDescLen;

                g_pCB->FunctionParams.pCmdExt->ActualRxPayloadLen = ActDataSize;

                /* Check that the space prepared by user for the response data is sufficient. */
                if(ActDataSize <= 0) {
                    g_pCB->FunctionParams.pCmdExt->RxPayloadLen = 0;
                } else {
                    /* In case the user supplied Rx buffer length which is smaller then the received data length, copy according to user length */
                    if (ActDataSize > g_pCB->FunctionParams.pCmdExt->RxPayloadLen) {
                        LengthToCopy = g_pCB->FunctionParams.pCmdExt->RxPayloadLen & (3);
                        AlignedLengthRecv = g_pCB->FunctionParams.pCmdExt->RxPayloadLen & (~3);
                    } else {
                        LengthToCopy = ActDataSize & (3);
                        AlignedLengthRecv = ActDataSize & (~3);
                    }
                    /*  Read 4 bytes aligned from interface */
                    /*  therefore check the requested length and read only  */
                    /*  4 bytes aligned data. The rest unaligned (if any) will be read */
                    /*  and copied to a TailBuffer  */

                    if( AlignedLengthRecv >= 4) {
                        NWP_IF_READ_CHECK(g_pCB->FD,
                                          g_pCB->FunctionParams.pCmdExt->pRxPayload,
                                          AlignedLengthRecv );

                    }
                    /*  copy the unaligned part, if any */
                    if( LengthToCopy > 0) {
                        NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer,4);
                        /*  copy TailBuffer unaligned part (1/2/3 bytes) */
                        memcpy(g_pCB->FunctionParams.pCmdExt->pRxPayload + AlignedLengthRecv,
                                  TailBuffer,
                                  LengthToCopy);
                        ActDataSize = ActDataSize-4;
                    }
                    /* In case the user supplied Rx buffer length which is smaller then the received data length, dump the rest */
                    if (ActDataSize > g_pCB->FunctionParams.pCmdExt->RxPayloadLen) {
                        /* calculate the rest of the data size to dump */
                        AlignedLengthRecv = ActDataSize - (g_pCB->FunctionParams.pCmdExt->RxPayloadLen & (~3));
                        while( AlignedLengthRecv > 0) {
                            NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer, 4 );
                            AlignedLengthRecv = AlignedLengthRecv - 4;
                        }
                    }
                }
            }
            break;

        default:
            /*  DUMMY_MSG_CLASS: Flow control message has no payload. */
            break;
    }

    if(AlignSize > 0) {
        NWP_IF_READ_CHECK(g_pCB->FD, uBuf.TempBuf, AlignSize);
    }

    _SL_DBG_CNT_INC(MsgCnt.Read);

    /*  Unmask Interrupt call */
    _spi.UnMaskIntHdlr();
    
    return SL_OS_RET_CODE_OK;
}

/* ******************************************************************************/
/*  _SlAsyncEventGenericHandler */
/* ******************************************************************************/
void cc3100_driver::_SlAsyncEventGenericHandler(void)
{
    uint32_t SlAsyncEvent = 0;
    uint8_t  OpcodeFound = FALSE; 
    uint8_t  i;
    
    uint32_t* pEventLocation  = NULL; /* This pointer will override the async buffer with the translated event type */
    _SlResponseHeader_t  *pHdr       = (_SlResponseHeader_t *)g_pCB->FunctionParams.AsyncExt.pAsyncBuf;


    /* if no async event registered nothing to do..*/
    if (g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler == NULL)
        return;

    /* Iterate through all the opcode in the table */
    for (i=0; i< (sizeof(OpcodeTranslateTable) / sizeof(OpcodeKeyVal_t)); i++)
    {
        if (OpcodeTranslateTable[i].opcode == pHdr->GenHeader.Opcode)
        {
            SlAsyncEvent = OpcodeTranslateTable[i].event;
            OpcodeFound = TRUE;
            break;
        }
    }

    /* No Async event found in the table */
    if (OpcodeFound == FALSE)
    {
        /* This case handles all the async events handlers of the DEVICE & SOCK Silos which are handled internally.
                 For these cases we send the async even buffer as is */
        g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler(g_pCB->FunctionParams.AsyncExt.pAsyncBuf);
    }
    else
    {
       /* calculate the event type location to be filled in the async buffer */
       pEventLocation = (uint32_t*)(g_pCB->FunctionParams.AsyncExt.pAsyncBuf + sizeof (_SlResponseHeader_t) - sizeof(SlAsyncEvent) );

       /* Override the async buffer (before the data starts ) with our event type  */
       *pEventLocation = SlAsyncEvent;

       /* call the event handler registered by the user with our async buffer which now holds
                the User's event type and its related data */
       g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler(pEventLocation);
    }
    
}


/* ******************************************************************************/
/*  _SlDrvMsgReadCmdCtx  */
/* ******************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvMsgReadCmdCtx(void)
{
    /*  after command response is received and isCmdRespWaited */
    /*  flag is set FALSE, it is necessary to read out all */
    /*  Async messages in Commands context, because ssiDma_IsrHandleSignalFromSlave */
    /*  could have dispatched some Async messages to g_NwpIf.CmdSyncObj */
    /*  after command response but before this response has been processed */
    /*  by spi_singleRead and isCmdRespWaited was set FALSE. */
    
    while (TRUE == g_pCB->IsCmdRespWaited) {
        
        if(_SL_PENDING_RX_MSG(g_pCB)) {
                       
            VERIFY_RET_OK(_SlDrvMsgRead());
            g_pCB->RxDoneCnt++;
            
            if (CMD_RESP_CLASS == g_pCB->FunctionParams.AsyncExt.RxMsgClass) {
                g_pCB->IsCmdRespWaited = FALSE;

                /*  In case CmdResp has been read without  waiting on CmdSyncObj -  that */
                /*  Sync object. That to prevent old signal to be processed. */
//#ifndef SL_PLATFORM_MULTI_THREADED 
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))              
                _nonos.sl_SyncObjClear(&g_pCB->CmdSyncObj);
#else                
                sl_SyncObjClear(&g_pCB->CmdSyncObj);
#endif                
            } else if (ASYNC_EVT_CLASS == g_pCB->FunctionParams.AsyncExt.RxMsgClass) {
                /*  If Async event has been read in CmdResp context, check whether */
                /*  there is a handler for this event. If there is, spawn specific */
                /*  handler. Otherwise free the event's buffer. */
                /*  This way there will be no "dry shots" from CmdResp context to */
                /*  temporary context, i.e less waste of CPU and faster buffer */
                /*  release. */
                _SlAsyncEventGenericHandler();
               
#ifdef SL_MEMORY_MGMT_DYNAMIC
                sl_Free(g_pCB->FunctionParams.AsyncExt.pAsyncBuf);
#else
                g_pCB->FunctionParams.AsyncExt.pAsyncBuf = NULL;
#endif
            }
        } else {
            /* CmdSyncObj will be signaled by IRQ */
            _SlDrvSyncObjWaitForever(&g_pCB->CmdSyncObj);
        }
    }
    
    /*  If there are more pending Rx Msgs after CmdResp is received, */
    /*  that means that these are Async, Dummy or Read Data Msgs. */
    /*  Spawn _SlDrvMsgReadSpawnCtx to trigger reading these messages from */
    /*  Temporary context. */
    /* sl_Spawn is activated, using a different context */
    _SlDrvObjUnLock(&g_pCB->GlobalLockObj);
    
    if(_SL_PENDING_RX_MSG(g_pCB)) {
//#ifndef SL_PLATFORM_MULTI_THREADED 
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))     
      _nonos._SlNonOsSpawn((_SlSpawnEntryFunc_t)&_SlDrvMsgReadSpawnCtx, NULL, 0);
#else
      sl_Spawn((_SlSpawnEntryFunc_t)&_SlDrvMsgReadSpawnCtx, NULL, 0);
#endif      
    }
    
    return SL_OS_RET_CODE_OK;
}

/* ******************************************************************************/
/*  _SlDrvMsgReadSpawnCtx                                                       */
/* ******************************************************************************/
/*
_SlReturnVal_t cc3100_driver::_SlDrvMsgReadSpawnCtx_(void *pValue)
{
	
#ifdef SL_POLLING_MODE_USED
    int16_t retCode = OSI_OK;
    //  for polling based systems 
    do {
        retCode = sl_LockObjLock(&g_pCB->GlobalLockObj, 0);
        if ( OSI_OK != retCode ) {
            if (TRUE == g_pCB->IsCmdRespWaited) {
                _SlDrvSyncObjSignal(&g_pCB->CmdSyncObj);
                return SL_RET_CODE_OK;
            }
        }

    } while (OSI_OK != retCode);

#else
    _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj);
#endif

    //  Messages might have been read by CmdResp context. Therefore after 
    //  getting LockObj, check again where the Pending Rx Msg is still present. 
    if(FALSE == (_SL_PENDING_RX_MSG(g_pCB))) {
        _SlDrvObjUnLock(&g_pCB->GlobalLockObj);
        return SL_RET_CODE_OK;
    }

    VERIFY_RET_OK(_SlDrvMsgRead());

    g_pCB->RxDoneCnt++;

    switch(g_pCB->FunctionParams.AsyncExt.RxMsgClass) {
        case ASYNC_EVT_CLASS:
            //  If got here and protected by LockObj a message is waiting  
            //  to be read 
            VERIFY_PROTOCOL(NULL != g_pCB->FunctionParams.AsyncExt.pAsyncBuf);

            _SlAsyncEventGenericHandler();

#ifdef SL_MEMORY_MGMT_DYNAMIC
        sl_Free(g_pCB->FunctionParams.AsyncExt.pAsyncBuf);
#else
        g_pCB->FunctionParams.AsyncExt.pAsyncBuf = NULL;
#endif
            break;
        case DUMMY_MSG_CLASS:
        case RECV_RESP_CLASS:
            // These types are legal in this context. Do nothing 
            break;
        case CMD_RESP_CLASS:
            // Command response is illegal in this context. 
            // No 'break' here: Assert! 
        default:
            VERIFY_PROTOCOL(0);
    }

    _SlDrvObjUnLock(&g_pCB->GlobalLockObj);

    return(SL_RET_CODE_OK);
}
*/
/* ******************************************************************************/
/*  _SlDrvClassifyRxMsg */
/* ******************************************************************************/
void cc3100_driver::_SlDrvClassifyRxMsg(_SlOpcode_t Opcode)
{
    _SlSpawnEntryFunc_t AsyncEvtHandler = NULL;
    _SlRxMsgClass_e     RxMsgClass  = CMD_RESP_CLASS;
    uint8_t             Silo;
    

	if (0 == (SL_OPCODE_SYNC & Opcode))
	{   /* Async event has received */
        
		if (SL_OPCODE_DEVICE_DEVICEASYNCDUMMY == Opcode)
		{ 
		    RxMsgClass = DUMMY_MSG_CLASS;
		}
		else if ( (SL_OPCODE_SOCKET_RECVASYNCRESPONSE == Opcode) || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE == Opcode) 
#ifndef SL_TINY_EXT                      
                    || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6 == Opcode) 
#endif                    
                 ) 
		{
			RxMsgClass = RECV_RESP_CLASS;
		}
		else
		{
            /* This is Async Event class message */
            RxMsgClass = ASYNC_EVT_CLASS;
        
		    /* Despite the fact that 4 bits are allocated in the SILO field, we actually have only 6 SILOs
		      So we can use the 8 options of SILO in look up table */
		    Silo = ((Opcode >> SL_OPCODE_SILO_OFFSET) & 0x7);

            VERIFY_PROTOCOL(Silo < (sizeof(RxMsgClassLUT)/sizeof(_SlSpawnEntryFunc_t)));

            /* Set the async event hander according to the LUT */
            AsyncEvtHandler = RxMsgClassLUT[Silo];
            
            if ((SL_OPCODE_NETAPP_HTTPGETTOKENVALUE == Opcode) || (SL_OPCODE_NETAPP_HTTPPOSTTOKENVALUE == Opcode))
            {
                AsyncEvtHandler = _SlDrvNetAppEventHandler;
            }
#ifndef SL_TINY_EXT            
            else if (SL_OPCODE_NETAPP_PINGREPORTREQUESTRESPONSE == Opcode)
            {
                AsyncEvtHandler = (_SlSpawnEntryFunc_t)_sl_HandleAsync_PingResponse;
            }
#endif
		}
	}

    g_pCB->FunctionParams.AsyncExt.RxMsgClass = RxMsgClass; 
    g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler = AsyncEvtHandler;

}

/* ******************************************************************************/
/*  _SlDrvRxHdrRead  */
/* ******************************************************************************/
_SlReturnVal_t  cc3100_driver::_SlDrvRxHdrRead(uint8_t *pBuf, uint8_t *pAlignSize)
{
    uint32_t       SyncCnt  = 0;
    uint8_t        ShiftIdx;    
    
#ifndef SL_IF_TYPE_UART
    /*  1. Write CNYS pattern to NWP when working in SPI mode only  */
    NWP_IF_WRITE_CHECK(g_pCB->FD, (uint8_t *)&g_H2NCnysPattern.Short, SYNC_PATTERN_LEN);
#endif
  
    /*  2. Read 4 bytes (protocol aligned) */
    NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[0], 4);
    _SL_DBG_SYNC_LOG(SyncCnt,pBuf);
 
    /* Wait for SYNC_PATTERN_LEN from the device */
    while ( ! N2H_SYNC_PATTERN_MATCH(pBuf, g_pCB->TxSeqNum) ) {
        /*  3. Debug limit of scan */
        if(SyncCnt >= SL_SYNC_SCAN_THRESHOLD){
        	printf("SPI Sync pattern match fault\n\r");
        }
        VERIFY_PROTOCOL(SyncCnt < SL_SYNC_SCAN_THRESHOLD);

        /*  4. Read next 4 bytes to Low 4 bytes of buffer */
        if(0 == (SyncCnt % (uint32_t)SYNC_PATTERN_LEN)) {
            NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[4], 4);
            _SL_DBG_SYNC_LOG(SyncCnt,pBuf);
        }

        /*  5. Shift Buffer Up for checking if the sync is shifted */
        for(ShiftIdx = 0; ShiftIdx< 7; ShiftIdx++)
        {
            pBuf[ShiftIdx] = pBuf[ShiftIdx+1];
        }             
        pBuf[7] = 0;

        SyncCnt++;
    }

    /*  5. Sync pattern found. If needed, complete number of read bytes to multiple of 4 (protocol align) */
    SyncCnt %= SYNC_PATTERN_LEN;

    if(SyncCnt > 0) {
        *(uint32_t *)&pBuf[0] = *(uint32_t *)&pBuf[4];
        NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[SYNC_PATTERN_LEN - SyncCnt], (uint16_t)SyncCnt);
    } else {
        NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[0], 4);
    }

    /*  6. Scan for Double pattern. */
    while ( N2H_SYNC_PATTERN_MATCH(pBuf, g_pCB->TxSeqNum) ) {
        _SL_DBG_CNT_INC(Work.DoubleSyncPattern);
        NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[0], SYNC_PATTERN_LEN);
    }
    g_pCB->TxSeqNum++;

    /*  7. Here we've read Generic Header (4 bytes). Read the Resp Specific header (4 more bytes). */
    NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[SYNC_PATTERN_LEN], _SL_RESP_SPEC_HDR_SIZE);

    /*  8. Here we've read the entire Resp Header. */
    /*     Return number bytes needed to be sent after read for NWP Rx 4-byte alignment (protocol alignment) */
    *pAlignSize = (uint8_t)((SyncCnt > 0) ? (SYNC_PATTERN_LEN - SyncCnt) : 0);

    return SL_RET_CODE_OK;
}

/* ***************************************************************************** */
/*  _SlDrvBasicCmd */
/* ***************************************************************************** */
typedef union {
    _BasicResponse_t	Rsp;
} _SlBasicCmdMsg_u;

#ifndef SL_TINY_EXT
int16_t cc3100_driver::_SlDrvBasicCmd(_SlOpcode_t Opcode)
{
    _SlBasicCmdMsg_u       Msg = {0};
    _SlCmdCtrl_t           CmdCtrl;

    CmdCtrl.Opcode = Opcode;
    CmdCtrl.TxDescLen = 0;
    CmdCtrl.RxDescLen = sizeof(_BasicResponse_t);


    VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL));

    return (int16_t)Msg.Rsp.status;
}

/*****************************************************************************
  _SlDrvCmdSend 
  Send SL command without waiting for command response 
  This function is unprotected and the caller should make 
  sure global lock is active
*****************************************************************************/
_SlReturnVal_t cc3100_driver::_SlDrvCmdSend(_SlCmdCtrl_t *pCmdCtrl, void *pTxRxDescBuff, _SlCmdExt_t *pCmdExt)
{
    _SlReturnVal_t RetVal;
    uint8_t        IsCmdRespWaitedOriginalVal;

    _SlFunctionParams_t originalFuncParms;

    /* save the current RespWait flag before clearing it */
    IsCmdRespWaitedOriginalVal = g_pCB->IsCmdRespWaited;

    /* save the current command parameters */
    memcpy(&originalFuncParms,  &g_pCB->FunctionParams, sizeof(_SlFunctionParams_t));

    g_pCB->IsCmdRespWaited = FALSE;
  
    SL_TRACE0(DBG_MSG, MSG_312, "_SlDrvCmdSend: call _SlDrvMsgWrite");

    /* send the message */
    RetVal = _SlDrvMsgWrite(pCmdCtrl, pCmdExt, (uint8_t*)pTxRxDescBuff);

    /* restore the original RespWait flag */
    g_pCB->IsCmdRespWaited = IsCmdRespWaitedOriginalVal;

    /* restore the original command parameters  */
    memcpy(&g_pCB->FunctionParams, &originalFuncParms, sizeof(_SlFunctionParams_t));

    return RetVal;


}
#endif

/* ***************************************************************************** */
/*  _SlDrvWaitForPoolObj */
/* ***************************************************************************** */
uint8_t cc3100_driver::_SlDrvWaitForPoolObj(uint8_t ActionID, uint8_t SocketID)
{
    uint8_t CurrObjIndex = MAX_CONCURRENT_ACTIONS;
    
    /* Get free object  */
    _SlDrvProtectionObjLockWaitForever();
    if (MAX_CONCURRENT_ACTIONS > g_pCB->FreePoolIdx) {
        /* save the current obj index */
        CurrObjIndex = g_pCB->FreePoolIdx;
        /* set the new free index */
#ifndef SL_TINY_EXT        
        if (MAX_CONCURRENT_ACTIONS > g_pCB->ObjPool[CurrObjIndex].NextIndex) {
            g_pCB->FreePoolIdx = g_pCB->ObjPool[CurrObjIndex].NextIndex;
        } 
        else
#endif         
        {            
            /* No further free actions available */
            g_pCB->FreePoolIdx = MAX_CONCURRENT_ACTIONS;
        }
    } else {
        _SlDrvProtectionObjUnLock();
        return CurrObjIndex;
    }
    g_pCB->ObjPool[CurrObjIndex].ActionID = (uint8_t)ActionID;
    if (SL_MAX_SOCKETS > SocketID) {
        g_pCB->ObjPool[CurrObjIndex].AdditionalData = SocketID;
    }
#ifndef SL_TINY_EXT    
    /*In case this action is socket related, SocketID bit will be on
    In case SocketID is set to SL_MAX_SOCKETS, the socket is not relevant to the action. In that case ActionID bit will be on */
    	while ( ( (SL_MAX_SOCKETS > SocketID) && (g_pCB->ActiveActionsBitmap & (1<<SocketID)) ) || 
            ( (g_pCB->ActiveActionsBitmap & (1<<ActionID)) && (SL_MAX_SOCKETS == SocketID) ) )
    {
        /* action in progress - move to pending list */
        g_pCB->ObjPool[CurrObjIndex].NextIndex = g_pCB->PendingPoolIdx;
        g_pCB->PendingPoolIdx = CurrObjIndex;
		_SlDrvProtectionObjUnLock();
        
        /* wait for action to be free */
        _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[CurrObjIndex].SyncObj);
        
        /* set params and move to active (remove from pending list at _SlDrvReleasePoolObj) */
        _SlDrvProtectionObjLockWaitForever();
    }
#endif
    /* mark as active. Set socket as active if action is on socket, otherwise mark action as active */
    if (SL_MAX_SOCKETS > SocketID) {
        g_pCB->ActiveActionsBitmap |= (1<<SocketID);
    } else {
        g_pCB->ActiveActionsBitmap |= (1<<ActionID);
    }
    /* move to active list  */
    g_pCB->ObjPool[CurrObjIndex].NextIndex = g_pCB->ActivePoolIdx;
    g_pCB->ActivePoolIdx = CurrObjIndex;
    /* unlock */
    _SlDrvProtectionObjUnLock();
    return CurrObjIndex;
}

/* ******************************************************************************/
/*  _SlDrvReleasePoolObj */
/* ******************************************************************************/
void cc3100_driver::_SlDrvReleasePoolObj(uint8_t ObjIdx)
{
#ifndef SL_TINY_EXT        
    uint8_t PendingIndex;
#endif

     _SlDrvProtectionObjLockWaitForever();

      /* In Tiny mode, there is only one object pool so no pending actions are available */
#ifndef SL_TINY_EXT
    /* go over the pending list and release other pending action if needed */
	PendingIndex = g_pCB->PendingPoolIdx;
        
	while(MAX_CONCURRENT_ACTIONS > PendingIndex)
	{
		/* In case this action is socket related, SocketID is in use, otherwise will be set to SL_MAX_SOCKETS */
		if ( (g_pCB->ObjPool[PendingIndex].ActionID == g_pCB->ObjPool[ObjIdx].ActionID) && 
			( (SL_MAX_SOCKETS == (g_pCB->ObjPool[PendingIndex].AdditionalData & BSD_SOCKET_ID_MASK)) || 
			((SL_MAX_SOCKETS > (g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK)) && ( (g_pCB->ObjPool[PendingIndex].AdditionalData & BSD_SOCKET_ID_MASK) == (g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK) ))) )
		{
			/* remove from pending list */
			_SlRemoveFromList(&g_pCB->PendingPoolIdx, PendingIndex);
			 _SlDrvSyncObjSignal(&g_pCB->ObjPool[PendingIndex].SyncObj);
			 break;
		}
		PendingIndex = g_pCB->ObjPool[PendingIndex].NextIndex;
	}
#endif

		if (SL_MAX_SOCKETS > (g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK))
		{
		/* unset socketID  */
			g_pCB->ActiveActionsBitmap &= ~(1<<(g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK));
		}
		else
		{
		/* unset actionID  */
			g_pCB->ActiveActionsBitmap &= ~(1<<g_pCB->ObjPool[ObjIdx].ActionID);
		}

    /* delete old data */
    g_pCB->ObjPool[ObjIdx].pRespArgs = NULL;
    g_pCB->ObjPool[ObjIdx].ActionID = 0;
    g_pCB->ObjPool[ObjIdx].AdditionalData = SL_MAX_SOCKETS;

    /* remove from active list */
    _SlRemoveFromList(&g_pCB->ActivePoolIdx, ObjIdx);
    /* move to free list */
    g_pCB->ObjPool[ObjIdx].NextIndex = g_pCB->FreePoolIdx;
    g_pCB->FreePoolIdx = ObjIdx;

    _SlDrvProtectionObjUnLock();
}

/* ******************************************************************************/
/* _SlRemoveFromList  */
/* ******************************************************************************/
void cc3100_driver::_SlRemoveFromList(uint8_t *ListIndex, uint8_t ItemIndex)
{
 #ifndef SL_TINY_EXT  
	uint8_t Idx;
#endif        
        
    if (MAX_CONCURRENT_ACTIONS == g_pCB->ObjPool[*ListIndex].NextIndex)
    {
        *ListIndex = MAX_CONCURRENT_ACTIONS;
    }
    /* As MAX_CONCURRENT_ACTIONS is equal to 1 in Tiny mode */
#ifndef SL_TINY_EXT
	/* need to remove the first item in the list and therefore update the global which holds this index */
	else if (*ListIndex == ItemIndex)
	{
		*ListIndex = g_pCB->ObjPool[ItemIndex].NextIndex;
	}
	else
	{
              Idx = *ListIndex;
      
              while(MAX_CONCURRENT_ACTIONS > Idx)
              {
                  /* remove from list */
                  if (g_pCB->ObjPool[Idx].NextIndex == ItemIndex)
                  {
                          g_pCB->ObjPool[Idx].NextIndex = g_pCB->ObjPool[ItemIndex].NextIndex;
                          break;
                  }

                  Idx = g_pCB->ObjPool[Idx].NextIndex;
              }
	}
#endif    
}

/* ******************************************************************************/
/*  _SlFindAndSetActiveObj                                                     */
/* ******************************************************************************/
_SlReturnVal_t cc3100_driver::_SlFindAndSetActiveObj(_SlOpcode_t  Opcode, uint8_t Sd)
{
    uint8_t ActiveIndex;

    ActiveIndex = g_pCB->ActivePoolIdx;
    /* go over the active list if exist to find obj waiting for this Async event */
    #ifndef SL_TINY_EXT    
		while (MAX_CONCURRENT_ACTIONS > ActiveIndex){
#else
        /* Only one Active action is availabe in tiny mode, so we can replace the loop with if condition */
        if (MAX_CONCURRENT_ACTIONS > ActiveIndex)
#endif
        /* unset the Ipv4\IPv6 bit in the opcode if family bit was set  */
        if (g_pCB->ObjPool[ActiveIndex].AdditionalData & SL_NETAPP_FAMILY_MASK) {
            Opcode &= ~SL_OPCODE_IPV6;
        }

        if ((g_pCB->ObjPool[ActiveIndex].ActionID == RECV_ID) && (Sd == g_pCB->ObjPool[ActiveIndex].AdditionalData) &&
                						( (SL_OPCODE_SOCKET_RECVASYNCRESPONSE == Opcode) || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE == Opcode)
#ifndef SL_TINY_EXT
                        || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6 == Opcode) 
#endif
                          ) 

               )
        {       
            g_pCB->FunctionParams.AsyncExt.ActionIndex = ActiveIndex;
            return SL_RET_CODE_OK;
        }
        /* In case this action is socket related, SocketID is in use, otherwise will be set to SL_MAX_SOCKETS */
        if ( (_SlActionLookupTable[ g_pCB->ObjPool[ActiveIndex].ActionID - MAX_SOCKET_ENUM_IDX].ActionAsyncOpcode == Opcode) &&
                ( ((Sd == (g_pCB->ObjPool[ActiveIndex].AdditionalData & BSD_SOCKET_ID_MASK) ) && (SL_MAX_SOCKETS > Sd)) || (SL_MAX_SOCKETS == (g_pCB->ObjPool[ActiveIndex].AdditionalData & BSD_SOCKET_ID_MASK)) ) ) {
            /* set handler */
            g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler = _SlActionLookupTable[ g_pCB->ObjPool[ActiveIndex].ActionID - MAX_SOCKET_ENUM_IDX].AsyncEventHandler;
            g_pCB->FunctionParams.AsyncExt.ActionIndex = ActiveIndex;
            return SL_RET_CODE_OK;
        }
        ActiveIndex = g_pCB->ObjPool[ActiveIndex].NextIndex;
    }

    return SL_RET_CODE_SELF_ERROR;

}

/* Wrappers for the object functions */

void  cc3100_driver::_SlDrvSyncObjWaitForever(_SlSyncObj_t *pSyncObj)
{
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))   
    OSI_RET_OK_CHECK(_nonos.sl_SyncObjWait(pSyncObj, SL_OS_WAIT_FOREVER));
#else    
    OSI_RET_OK_CHECK(sl_SyncObjWait(pSyncObj, SL_OS_WAIT_FOREVER));
#endif   
}

void  cc3100_driver::_SlDrvSyncObjSignal(_SlSyncObj_t *pSyncObj)
{
//#ifndef SL_PLATFORM_MULTI_THREADED 
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))  
    OSI_RET_OK_CHECK(_nonos.sl_SyncObjSignal(pSyncObj));
#else    
    OSI_RET_OK_CHECK(sl_SyncObjSignal(pSyncObj));
#endif   
}

void cc3100_driver::_SlDrvObjLockWaitForever(_SlLockObj_t *pLockObj)
{
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))  
    OSI_RET_OK_CHECK(_nonos.sl_LockObjLock(pLockObj, SL_OS_WAIT_FOREVER));
#else    
    OSI_RET_OK_CHECK(sl_LockObjLock(pLockObj, SL_OS_WAIT_FOREVER));
#endif    
}

void cc3100_driver::_SlDrvProtectionObjLockWaitForever()
{
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))    
    OSI_RET_OK_CHECK(_nonos.sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
#else
    OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER));
#endif
}

void cc3100_driver::_SlDrvObjUnLock(_SlLockObj_t *pLockObj)
{
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))    
    OSI_RET_OK_CHECK(_nonos.sl_LockObjUnlock(pLockObj));
#else    
    OSI_RET_OK_CHECK(sl_LockObjUnlock(pLockObj));
#endif
}

void cc3100_driver::_SlDrvProtectionObjUnLock()
{
//#ifndef SL_PLATFORM_MULTI_THREADED
#if (!defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN))   
    OSI_RET_OK_CHECK(_nonos.sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
#else    
    OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj));
#endif    
}


void cc3100_driver::_SlDrvMemZero(void* Addr, uint16_t size)
{
    memset(Addr, 0, size);
}


void cc3100_driver::_SlDrvResetCmdExt(_SlCmdExt_t* pCmdExt)
{
    _SlDrvMemZero(pCmdExt, sizeof (_SlCmdExt_t));
}

}//namespace mbed_cc3100