cc3100_Socket_Wifi_Server with Ethernet Interface not working

Dependencies:   EthernetInterface mbed-rtos mbed

Fork of cc3100_Test_Demo by David Fletcher

simplelink/cc3100_socket.cpp

Committer:
dflet
Date:
2015-02-10
Revision:
0:e89ba455dbcf

File content as of revision 0:e89ba455dbcf:

/*
 * socket.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 "cc3100_socket.h"

namespace mbed_cc3100 {


cc3100_socket::cc3100_socket(cc3100_driver &driver, cc3100_nonos &nonos)
    : _driver(driver), _nonos(nonos)
{

}

cc3100_socket::~cc3100_socket()
{

}

/*******************************************************************************/
/* Functions                                                                   */
/*******************************************************************************/

/* ******************************************************************************/
/*  _sl_BuildAddress */
/* ******************************************************************************/
void cc3100_socket::_sl_BuildAddress(const SlSockAddr_t *addr, int16_t addrlen, _SocketAddrCommand_u *pCmd)
{
    /*  Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 */
    /*  is possible as int32_t as these parameters are in the same offset and size for these */
    /*  three families. */
    pCmd->IpV4.FamilyAndFlags = (addr->sa_family << 4) & 0xF0;
    pCmd->IpV4.port = ((SlSockAddrIn_t *)addr)->sin_port;

    if(SL_AF_INET == addr->sa_family) {
        pCmd->IpV4.address  = ((SlSockAddrIn_t *)addr)->sin_addr.s_addr;
    } else if (SL_AF_INET6_EUI_48 == addr->sa_family ) {
        memcpy( pCmd->IpV6EUI48.address,((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, 6);
    }
#ifdef SL_SUPPORT_IPV6
    else {
        memcpy(pCmd->IpV6.address, ((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, 16 );
    }
#endif
}

/* ******************************************************************************/
/*  _sl_TruncatePayloadByProtocol */
/* ******************************************************************************/
uint16_t cc3100_socket::_sl_TruncatePayloadByProtocol(const int16_t sd,const uint16_t length)
{
    uint16_t maxLength;

    switch(sd & SL_SOCKET_PAYLOAD_TYPE_MASK) {
        case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4:
            maxLength = 1472;
            break;

        case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4:
            maxLength = 1460;
            break;

        case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6:
            maxLength = 1452;
            break;

        case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6:
            maxLength = 1440;
            break;
        case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4_SECURE:
        case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4_SECURE:
            maxLength = 1402;
            break;
        case SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6_SECURE:
        case SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6_SECURE:
            maxLength = 1396;
            break;
        case SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER:
            maxLength = 1476;
            break;
        case SL_SOCKET_PAYLOAD_TYPE_RAW_PACKET:
            maxLength = 1514;
            break;
        case SL_SOCKET_PAYLOAD_TYPE_RAW_IP4:
            maxLength = 1480;
            break;
        default:
            maxLength = 1440;
            break;
    }

    if( length > maxLength ) {
        return maxLength;
    } else {
        return length;
    }
}

/*******************************************************************************/
/*  _sl_ParseAddress */
/*******************************************************************************/
void cc3100_socket::_sl_ParseAddress(_SocketAddrResponse_u    *pRsp, SlSockAddr_t *addr, SlSocklen_t *addrlen)
{
    /*  Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 */
    /*  is possible as long as these parameters are in the same offset and size for these */
    /*  three families. */
    addr->sa_family                 = pRsp->IpV4.family;
    ((SlSockAddrIn_t *)addr)->sin_port = pRsp->IpV4.port;

    *addrlen = (SL_AF_INET == addr->sa_family) ? sizeof(SlSockAddrIn_t) : sizeof(SlSockAddrIn6_t);

    if(SL_AF_INET == addr->sa_family) {
        ((SlSockAddrIn_t *)addr)->sin_addr.s_addr  = pRsp->IpV4.address;
    } else if (SL_AF_INET6_EUI_48 == addr->sa_family ) {
        memcpy(((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, pRsp->IpV6EUI48.address, 6);
    }
#ifdef SL_SUPPORT_IPV6
    else {
        memcpy(((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, pRsp->IpV6.address, 16);
    }
#endif
}

/*******************************************************************************/
/* sl_Socket */
/*******************************************************************************/
typedef union {
    uint32_t                Dummy;
    _SocketCommand_t 	Cmd;
    _SocketResponse_t	Rsp;
} _SlSockSocketMsg_u;

const _SlCmdCtrl_t _SlSockSocketCmdCtrl = {
    SL_OPCODE_SOCKET_SOCKET,
    sizeof(_SocketCommand_t),
    sizeof(_SocketResponse_t)
};

#if _SL_INCLUDE_FUNC(sl_Socket)
int16_t cc3100_socket::sl_Socket(int16_t Domain, int16_t Type, int16_t Protocol)
{
    _SlSockSocketMsg_u  Msg;

    Msg.Cmd.Domain	    = (uint8_t)Domain;
    Msg.Cmd.Type     	= (uint8_t)Type;
    Msg.Cmd.Protocol 	= (uint8_t)Protocol;

    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSockSocketCmdCtrl, &Msg, NULL));

    if( Msg.Rsp.statusOrLen < 0 ) {
        return( Msg.Rsp.statusOrLen );
    } else {
        return (int16_t)((uint8_t)Msg.Rsp.sd);
    }
}
#endif

/*******************************************************************************/
/*  sl_Close  */
/*******************************************************************************/
typedef union {
    _CloseCommand_t	    Cmd;
    _SocketResponse_t	Rsp;
} _SlSockCloseMsg_u;

const _SlCmdCtrl_t _SlSockCloseCmdCtrl = {
    SL_OPCODE_SOCKET_CLOSE,
    sizeof(_CloseCommand_t),
    sizeof(_SocketResponse_t)
};

#if _SL_INCLUDE_FUNC(sl_Close)
int16_t cc3100_socket::sl_Close(int16_t sd)
{
    _SlSockCloseMsg_u   Msg;

    Msg.Cmd.sd = (uint8_t)sd;

    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSockCloseCmdCtrl, &Msg, NULL));

    return Msg.Rsp.statusOrLen;
}
#endif

/*******************************************************************************/
/*  sl_Bind */
/*******************************************************************************/
typedef union {
    _SocketAddrCommand_u    Cmd;
    _SocketResponse_t	    Rsp;
} _SlSockBindMsg_u;

#if _SL_INCLUDE_FUNC(sl_Bind)
int16_t cc3100_socket::sl_Bind(int16_t sd, const SlSockAddr_t *addr, int16_t addrlen)
{
    _SlSockBindMsg_u    Msg;
    _SlCmdCtrl_t         CmdCtrl = {0, 0, sizeof(_SocketResponse_t)};

    switch(addr->sa_family) {
        case SL_AF_INET :
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
            break;
        case SL_AF_INET6_EUI_48:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t);
            break;
#ifdef SL_SUPPORT_IPV6
        case AF_INET6:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t);
            break;
#endif
        case SL_AF_RF   :
        default:
            return SL_RET_CODE_INVALID_INPUT;
    }

    Msg.Cmd.IpV4.lenOrPadding = 0;
    Msg.Cmd.IpV4.sd = (uint8_t)sd;

    _sl_BuildAddress(addr, addrlen, &Msg.Cmd);

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

    return Msg.Rsp.statusOrLen;
}
#endif

/*******************************************************************************/
/*  sl_Sendto */
/*******************************************************************************/
typedef union {
    _SocketAddrCommand_u    Cmd;
    /*  no response for 'sendto' commands*/
} _SlSendtoMsg_u;

#if _SL_INCLUDE_FUNC(sl_SendTo)
int16_t cc3100_socket::sl_SendTo(int16_t sd, const void *pBuf, int16_t Len, int16_t flags, const SlSockAddr_t *to, SlSocklen_t tolen)
{
    _SlSendtoMsg_u   Msg;
    _SlCmdCtrl_t     CmdCtrl = {0, 0, 0};
    _SlCmdExt_t      CmdExt;
    uint16_t         ChunkLen;
    int16_t          RetVal;

    CmdExt.TxPayloadLen = (uint16_t)Len;
    CmdExt.RxPayloadLen = 0;
    CmdExt.pTxPayload = (unsigned char *)pBuf;
    CmdExt.pRxPayload = NULL;


    switch(to->sa_family) {
        case SL_AF_INET:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
            break;
        case SL_AF_INET6_EUI_48:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t);
            break;
#ifdef SL_SUPPORT_IPV6
        case AF_INET6:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO_V6;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t);
            break;
#endif
        case SL_AF_RF:
        default:
            return SL_RET_CODE_INVALID_INPUT;
    }

    ChunkLen = _sl_TruncatePayloadByProtocol(sd,Len);
    Msg.Cmd.IpV4.lenOrPadding = ChunkLen;
    CmdExt.TxPayloadLen = ChunkLen;

    Msg.Cmd.IpV4.sd = (unsigned char)sd;

    _sl_BuildAddress(to, tolen, &Msg.Cmd);
    
    Msg.Cmd.IpV4.FamilyAndFlags |= flags & 0x0F;
    
    do {
        RetVal = _driver._SlDrvDataWriteOp((_SlSd_t)sd, &CmdCtrl, &Msg, &CmdExt);
        
        if(SL_OS_RET_CODE_OK == RetVal) {
            CmdExt.pTxPayload += ChunkLen;
            ChunkLen = (uint16_t)((unsigned char *)pBuf + Len - CmdExt.pTxPayload);
            ChunkLen = _sl_TruncatePayloadByProtocol(sd,ChunkLen);
            CmdExt.TxPayloadLen = ChunkLen;
            Msg.Cmd.IpV4.lenOrPadding = ChunkLen;
        } else {
            return RetVal;
        }
    } while(ChunkLen > 0);

    return (int16_t)Len;
}
#endif

/*******************************************************************************/
/*  sl_Recvfrom */
/*******************************************************************************/
typedef union {
    _sendRecvCommand_t	    Cmd;
    _SocketAddrResponse_u	Rsp;
} _SlRecvfromMsg_u;

const _SlCmdCtrl_t _SlRecvfomCmdCtrl = {
    SL_OPCODE_SOCKET_RECVFROM,
    sizeof(_sendRecvCommand_t),
    sizeof(_SocketAddrResponse_u)
};

#if _SL_INCLUDE_FUNC(sl_RecvFrom)
int16_t cc3100_socket::sl_RecvFrom(int16_t sd, void *buf, int16_t Len, int16_t flags, SlSockAddr_t *from, SlSocklen_t *fromlen)
{
    _SlRecvfromMsg_u    Msg;
    _SlCmdExt_t         CmdExt;
    int16_t                 RetVal;

    CmdExt.TxPayloadLen = 0;
    CmdExt.RxPayloadLen = Len;
    CmdExt.pTxPayload = NULL;
    CmdExt.pRxPayload = (uint8_t *)buf;


    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.StatusOrLen = Len;
    /*  no size truncation in recv path */
    CmdExt.RxPayloadLen = Msg.Cmd.StatusOrLen;

    if(sizeof(SlSockAddrIn_t) == *fromlen) {
        Msg.Cmd.FamilyAndFlags = SL_AF_INET;
    } else if (sizeof(SlSockAddrIn6_t) == *fromlen) {
        Msg.Cmd.FamilyAndFlags = SL_AF_INET6;
    } else {
        return SL_RET_CODE_INVALID_INPUT;
    }

    Msg.Cmd.FamilyAndFlags = (Msg.Cmd.FamilyAndFlags << 4) & 0xF0;
    Msg.Cmd.FamilyAndFlags |= flags & 0x0F;

    RetVal = _driver._SlDrvDataReadOp((_SlSd_t)sd, (_SlCmdCtrl_t *)&_SlRecvfomCmdCtrl, &Msg, &CmdExt);
    if( RetVal != SL_OS_RET_CODE_OK ) {
        return RetVal;
    }

    RetVal = Msg.Rsp.IpV4.statusOrLen;

    if(RetVal >= 0) {
        VERIFY_PROTOCOL(sd == Msg.Rsp.IpV4.sd);
#if 0
        _sl_ParseAddress(&Msg.Rsp, from, fromlen);
#else
        from->sa_family = Msg.Rsp.IpV4.family;
        if(SL_AF_INET == from->sa_family) {
            ((SlSockAddrIn_t *)from)->sin_port = Msg.Rsp.IpV4.port;
            ((SlSockAddrIn_t *)from)->sin_addr.s_addr = Msg.Rsp.IpV4.address;
            *fromlen = sizeof(SlSockAddrIn_t);
        } else if (SL_AF_INET6_EUI_48 == from->sa_family ) {
            ((SlSockAddrIn6_t *)from)->sin6_port  = Msg.Rsp.IpV6EUI48.port;
            memcpy(((SlSockAddrIn6_t *)from)->sin6_addr._S6_un._S6_u8, Msg.Rsp.IpV6EUI48.address, 6);
        }
#ifdef SL_SUPPORT_IPV6
        else if(AF_INET6 == from->sa_family) {
            VERIFY_PROTOCOL(*fromlen >= sizeof(sockaddr_in6));

            ((sockaddr_in6 *)from)->sin6_port = Msg.Rsp.IpV6.port;
            memcpy(((sockaddr_in6 *)from)->sin6_addr._S6_un._S6_u32, Msg.Rsp.IpV6.address, 16);
            *fromlen = sizeof(sockaddr_in6);
        }
#endif
#endif
    }

    return (int16_t)RetVal;
}
#endif

/*******************************************************************************/
/*  sl_Connect */
/*******************************************************************************/
typedef union {
    _SocketAddrCommand_u    Cmd;
    _SocketResponse_t	    Rsp;
} _SlSockConnectMsg_u;

#if _SL_INCLUDE_FUNC(sl_Connect)
int16_t cc3100_socket::sl_Connect(int16_t sd, const SlSockAddr_t *addr, int16_t addrlen)
{
    _SlSockConnectMsg_u  Msg;
    _SlReturnVal_t       RetVal;
    _SlCmdCtrl_t         CmdCtrl = {0, 0, sizeof(_SocketResponse_t)};
    _SocketResponse_t    AsyncRsp;
    uint8_t ObjIdx = MAX_CONCURRENT_ACTIONS;


    switch(addr->sa_family) {
        case SL_AF_INET :
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t);
            break;
        case  SL_AF_INET6_EUI_48:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT_V6;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t);
            break;
#ifdef SL_SUPPORT_IPV6
        case AF_INET6:
            CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT_V6;
            CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t);
            break;
#endif
        case SL_AF_RF   :
        default:
            return SL_RET_CODE_INVALID_INPUT;
    }

    Msg.Cmd.IpV4.lenOrPadding = 0;
    Msg.Cmd.IpV4.sd = (uint8_t)sd;

    _sl_BuildAddress(addr, addrlen, &Msg.Cmd);

    /* Use Obj to issue the command, if not available try later */
    ObjIdx = (uint8_t)_driver._SlDrvWaitForPoolObj(CONNECT_ID, (uint8_t)(sd  & BSD_SOCKET_ID_MASK));

    if (MAX_CONCURRENT_ACTIONS == ObjIdx) {
        return SL_POOL_IS_EMPTY;
    }
    OSI_RET_OK_CHECK(_nonos.sl_LockObjLock(&g_pCB->ProtectionLockObj, NON_OS_LOCK_OBJ_UNLOCK_VALUE, NON_OS_LOCK_OBJ_LOCK_VALUE, SL_OS_WAIT_FOREVER));

    g_pCB->ObjPool[ObjIdx].pRespArgs =  (uint8_t *)&AsyncRsp;

    OSI_RET_OK_CHECK(_nonos.sl_LockObjUnlock(&g_pCB->ProtectionLockObj, NON_OS_LOCK_OBJ_UNLOCK_VALUE));

    /* send the command */
    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL));
    VERIFY_PROTOCOL(Msg.Rsp.sd == sd)

    RetVal = Msg.Rsp.statusOrLen;

    if(SL_RET_CODE_OK == RetVal) {
        /*  wait for async and get Data Read parameters */
        OSI_RET_OK_CHECK(_nonos.sl_SyncObjWait(&g_pCB->ObjPool[ObjIdx].SyncObj, NON_OS_SYNC_OBJ_SIGNAL_VALUE, NON_OS_SYNC_OBJ_CLEAR_VALUE, SL_OS_WAIT_FOREVER));

        VERIFY_PROTOCOL(AsyncRsp.sd == sd);

        RetVal = AsyncRsp.statusOrLen;
    }
    _driver._SlDrvReleasePoolObj(ObjIdx);
    return RetVal;
}
#endif

/*******************************************************************************/
/*  sl_Send */
/*******************************************************************************/
typedef union {
    _sendRecvCommand_t    Cmd;
    /*  no response for 'sendto' commands*/
} _SlSendMsg_u;

const _SlCmdCtrl_t _SlSendCmdCtrl = {
    SL_OPCODE_SOCKET_SEND,
    sizeof(_sendRecvCommand_t),
    0
};

#if _SL_INCLUDE_FUNC(sl_Send)
int16_t cc3100_socket::sl_Send(int16_t sd, const void *pBuf, int16_t Len, int16_t flags)
{
    _SlSendMsg_u   Msg;
    _SlCmdExt_t    CmdExt;
    uint16_t         ChunkLen;
    int16_t            RetVal;
    uint32_t         tempVal;
    uint8_t  runSingleChunk = FALSE;

    CmdExt.TxPayloadLen = Len;
    CmdExt.RxPayloadLen = 0;
    CmdExt.pTxPayload = (uint8_t *)pBuf;

    /* Only for RAW transceiver type socket, relay the flags parameter in the 2 bytes (4 byte aligned) before the actual payload */
    if ((sd & SL_SOCKET_PAYLOAD_TYPE_MASK) == SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER) {
        tempVal = flags;
        CmdExt.pRxPayload = (uint8_t *)&tempVal;
        CmdExt.RxPayloadLen = 4;
        g_pCB->RelayFlagsViaRxPayload = TRUE;
        runSingleChunk = TRUE;
    } else {
        CmdExt.pRxPayload = NULL;
    }

    ChunkLen = _sl_TruncatePayloadByProtocol(sd,Len);
    CmdExt.TxPayloadLen = ChunkLen;

    Msg.Cmd.StatusOrLen = ChunkLen;
    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.FamilyAndFlags |= flags & 0x0F;

    do {
        RetVal = _driver._SlDrvDataWriteOp((uint8_t)sd, (_SlCmdCtrl_t *)&_SlSendCmdCtrl, &Msg, &CmdExt);
        if(SL_OS_RET_CODE_OK == RetVal) {
            CmdExt.pTxPayload += ChunkLen;
            ChunkLen = (uint8_t *)pBuf + Len - CmdExt.pTxPayload;
            ChunkLen = _sl_TruncatePayloadByProtocol(sd,ChunkLen);
            CmdExt.TxPayloadLen = ChunkLen;
            Msg.Cmd.StatusOrLen = ChunkLen;
        } else {
            return RetVal;
        }
    } while((ChunkLen > 0) && (runSingleChunk==FALSE));

    return (int16_t)Len;
}
#endif

/*******************************************************************************/
/*  sl_Listen */
/*******************************************************************************/
typedef union {
    _ListenCommand_t    Cmd;
    _BasicResponse_t    Rsp;
} _SlListenMsg_u;

const _SlCmdCtrl_t _SlListenCmdCtrl = {
    SL_OPCODE_SOCKET_LISTEN,
    sizeof(_ListenCommand_t),
    sizeof(_BasicResponse_t),
};

#if _SL_INCLUDE_FUNC(sl_Listen)
int16_t cc3100_socket::sl_Listen(int16_t sd, int16_t backlog)
{
    _SlListenMsg_u  Msg;

    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.backlog = (uint8_t)backlog;

    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlListenCmdCtrl, &Msg, NULL));

    return (int16_t)Msg.Rsp.status;
}
#endif

/*******************************************************************************/
/*  sl_Accept */
/*******************************************************************************/
typedef union {
    _AcceptCommand_t    Cmd;
    _SocketResponse_t   Rsp;
} _SlSockAcceptMsg_u;

const _SlCmdCtrl_t _SlAcceptCmdCtrl = {
    SL_OPCODE_SOCKET_ACCEPT,
    sizeof(_AcceptCommand_t),
    sizeof(_BasicResponse_t),
};

#if _SL_INCLUDE_FUNC(sl_Accept)
int16_t cc3100_socket::sl_Accept(int16_t sd, SlSockAddr_t *addr, SlSocklen_t *addrlen)
{
    _SlSockAcceptMsg_u      Msg;
    _SlReturnVal_t          RetVal;
    _SocketAddrResponse_u   AsyncRsp;

    uint8_t ObjIdx = MAX_CONCURRENT_ACTIONS;


    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.family = (sizeof(SlSockAddrIn_t) == *addrlen) ? SL_AF_INET : SL_AF_INET6;

    /* Use Obj to issue the command, if not available try later */
    ObjIdx = (uint8_t)_driver._SlDrvWaitForPoolObj(ACCEPT_ID, (uint8_t)(sd  & BSD_SOCKET_ID_MASK));

    if (MAX_CONCURRENT_ACTIONS == ObjIdx) {
        return SL_POOL_IS_EMPTY;
    }

    OSI_RET_OK_CHECK(_nonos.sl_LockObjLock(&g_pCB->ProtectionLockObj, NON_OS_LOCK_OBJ_UNLOCK_VALUE, NON_OS_LOCK_OBJ_LOCK_VALUE, SL_OS_WAIT_FOREVER));

    g_pCB->ObjPool[ObjIdx].pRespArgs = (uint8_t *)&AsyncRsp;

    OSI_RET_OK_CHECK(_nonos.sl_LockObjUnlock(&g_pCB->ProtectionLockObj, NON_OS_LOCK_OBJ_UNLOCK_VALUE));
    /* send the command */
    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlAcceptCmdCtrl, &Msg, NULL));
    VERIFY_PROTOCOL(Msg.Rsp.sd == sd);

    RetVal = Msg.Rsp.statusOrLen;

    if(SL_OS_RET_CODE_OK == RetVal) {
        /*  wait for async and get Data Read parameters */
        OSI_RET_OK_CHECK(_nonos.sl_SyncObjWait(&g_pCB->ObjPool[ObjIdx].SyncObj, NON_OS_SYNC_OBJ_SIGNAL_VALUE, NON_OS_SYNC_OBJ_CLEAR_VALUE, SL_OS_WAIT_FOREVER));

        VERIFY_PROTOCOL(AsyncRsp.IpV4.sd == sd);

        RetVal = AsyncRsp.IpV4.statusOrLen;
        if( (NULL != addr) && (NULL != addrlen) ) {
#if 0 /*  Kept for backup */
            _sl_ParseAddress(&AsyncRsp, addr, addrlen);
#else
            addr->sa_family = AsyncRsp.IpV4.family;

            if(SL_AF_INET == addr->sa_family) {
                if( *addrlen == sizeof( SlSockAddrIn_t ) ) {
                    ((SlSockAddrIn_t *)addr)->sin_port         = AsyncRsp.IpV4.port;
                    ((SlSockAddrIn_t *)addr)->sin_addr.s_addr  = AsyncRsp.IpV4.address;
                } else {
                    *addrlen = 0;
                }
            } else if (SL_AF_INET6_EUI_48 == addr->sa_family ) {
                if( *addrlen == sizeof( SlSockAddrIn6_t ) ) {
                    ((SlSockAddrIn6_t *)addr)->sin6_port                   = AsyncRsp.IpV6EUI48.port    ;
                    /*  will be called from here and from _sl_BuildAddress*/
                    memcpy(((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, AsyncRsp.IpV6EUI48.address, 6);
                } else {
                    *addrlen = 0;
                }
            }
#ifdef SL_SUPPORT_IPV6
            else {
                if( *addrlen == sizeof( sockaddr_in6 ) ) {
                    ((sockaddr_in6 *)addr)->sin6_port                   = AsyncRsp.IpV6.port    ;
                    memcpy(((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, AsyncRsp.IpV6.address, 16);
                } else {
                    *addrlen = 0;
                }
            }
#endif
#endif
        }
    }

    _driver._SlDrvReleasePoolObj(ObjIdx);
    return (int16_t)RetVal;
}
#endif


/*******************************************************************************/
/*  sl_Htonl */
/*******************************************************************************/
uint32_t cc3100_socket::sl_Htonl( uint32_t val )
{
    uint32_t i = 1;
    int8_t *p = (int8_t *)&i;
    if (p[0] == 1) { /* little endian */
        p[0] = ((int8_t* )&val)[3];
        p[1] = ((int8_t* )&val)[2];
        p[2] = ((int8_t* )&val)[1];
        p[3] = ((int8_t* )&val)[0];
        return i;
    } else { /* big endian */
        return val;
    }
}

/*******************************************************************************/
/*  sl_Htonl */
/*******************************************************************************/
uint16_t cc3100_socket::sl_Htons( uint16_t val )
{
    int16_t i = 1;
    int8_t *p = (int8_t *)&i;
    if (p[0] == 1) { /* little endian */
        p[0] = ((int8_t* )&val)[1];
        p[1] = ((int8_t* )&val)[0];
        return i;
    } else { /* big endian */
        return val;
    }
}

/*******************************************************************************/
/*  sl_Recv */
/*******************************************************************************/
typedef union {
    _sendRecvCommand_t  Cmd;
    _SocketResponse_t   Rsp;
} _SlRecvMsg_u;

const _SlCmdCtrl_t _SlRecvCmdCtrl = {
    SL_OPCODE_SOCKET_RECV,
    sizeof(_sendRecvCommand_t),
    sizeof(_SocketResponse_t)
};

#if _SL_INCLUDE_FUNC(sl_Recv)
int16_t cc3100_socket::sl_Recv(int16_t sd, void *pBuf, int16_t Len, int16_t flags)
{
    _SlRecvMsg_u    Msg;
    _SlCmdExt_t     CmdExt;
    _SlReturnVal_t status;

    CmdExt.TxPayloadLen = 0;
    CmdExt.RxPayloadLen = Len;
    CmdExt.pTxPayload = NULL;
    CmdExt.pRxPayload = (uint8_t *)pBuf;

    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.StatusOrLen = Len;

    /*  no size truncation in recv path */
    CmdExt.RxPayloadLen = Msg.Cmd.StatusOrLen;

    Msg.Cmd.FamilyAndFlags = flags & 0x0F;

    status = _driver._SlDrvDataReadOp((_SlSd_t)sd, (_SlCmdCtrl_t *)&_SlRecvCmdCtrl, &Msg, &CmdExt);
    if( status != SL_OS_RET_CODE_OK ) {
        return status;
    }

    /*  if the Device side sends less than expected it is not the Driver's role */
    /*  the returned value could be smaller than the requested size */
    return (int16_t)Msg.Rsp.statusOrLen;
}
#endif

/*******************************************************************************/
/*  sl_SetSockOpt */
/*******************************************************************************/
typedef union {
    _setSockOptCommand_t    Cmd;
    _SocketResponse_t       Rsp;
} _SlSetSockOptMsg_u;

const _SlCmdCtrl_t _SlSetSockOptCmdCtrl = {
    SL_OPCODE_SOCKET_SETSOCKOPT,
    sizeof(_setSockOptCommand_t),
    sizeof(_SocketResponse_t)
};

#if _SL_INCLUDE_FUNC(sl_SetSockOpt)
int16_t cc3100_socket::sl_SetSockOpt(int16_t sd, int16_t level, int16_t optname, const void *optval, SlSocklen_t optlen)
{
    _SlSetSockOptMsg_u    Msg;
    _SlCmdExt_t           CmdExt;

    CmdExt.TxPayloadLen = optlen;
    CmdExt.RxPayloadLen = 0;
    CmdExt.pTxPayload = (uint8_t *)optval;
    CmdExt.pRxPayload = NULL;

    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.level = (uint8_t)level;
    Msg.Cmd.optionLen = (uint8_t)optlen;
    Msg.Cmd.optionName = (uint8_t)optname;

    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSetSockOptCmdCtrl, &Msg, &CmdExt));

    return (int16_t)Msg.Rsp.statusOrLen;
}
#endif

/*******************************************************************************/
/*  sl_GetSockOpt */
/*******************************************************************************/
typedef union {
    _getSockOptCommand_t    Cmd;
    _getSockOptResponse_t   Rsp;
} _SlGetSockOptMsg_u;

const _SlCmdCtrl_t _SlGetSockOptCmdCtrl = {
    SL_OPCODE_SOCKET_GETSOCKOPT,
    sizeof(_getSockOptCommand_t),
    sizeof(_getSockOptResponse_t)
};

#if _SL_INCLUDE_FUNC(sl_GetSockOpt)
int16_t cc3100_socket::sl_GetSockOpt(int16_t sd, int16_t level, int16_t optname, void *optval, SlSocklen_t *optlen)
{
    _SlGetSockOptMsg_u    Msg;
    _SlCmdExt_t           CmdExt;

    if (*optlen == 0) {
        return SL_EZEROLEN;
    }
    CmdExt.TxPayloadLen = 0;
    CmdExt.RxPayloadLen = *optlen;
    CmdExt.pTxPayload = NULL;
    CmdExt.pRxPayload = (uint8_t*)optval;
    CmdExt.ActualRxPayloadLen = 0;

    Msg.Cmd.sd = (uint8_t)sd;
    Msg.Cmd.level = (uint8_t)level;
    Msg.Cmd.optionLen = (uint8_t)(*optlen);
    Msg.Cmd.optionName = (uint8_t)optname;

    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlGetSockOptCmdCtrl, &Msg, &CmdExt));

    if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) {
        *optlen = Msg.Rsp.optionLen;
        return SL_ESMALLBUF;
    } else {
        *optlen = (uint8_t)CmdExt.ActualRxPayloadLen;
    }
    return (int16_t)Msg.Rsp.status;
}
#endif

/*******************************************************************************/
/*  sl_Select */
/* ******************************************************************************/
typedef union {
    _SelectCommand_t   Cmd;
    _BasicResponse_t   Rsp;
} _SlSelectMsg_u;

const _SlCmdCtrl_t _SlSelectCmdCtrl = {
    SL_OPCODE_SOCKET_SELECT,
    sizeof(_SelectCommand_t),
    sizeof(_BasicResponse_t)
};

#if _SL_INCLUDE_FUNC(sl_Select)
int16_t cc3100_socket::sl_Select(int16_t nfds, SlFdSet_t *readsds, SlFdSet_t *writesds, SlFdSet_t *exceptsds, SlTimeval_t *timeout)
{
    _SlSelectMsg_u          Msg;
    _SelectAsyncResponse_t  AsyncRsp;
    uint8_t ObjIdx = MAX_CONCURRENT_ACTIONS;

    Msg.Cmd.nfds          = (uint8_t)nfds;
    Msg.Cmd.readFdsCount  = 0;
    Msg.Cmd.writeFdsCount = 0;

    Msg.Cmd.readFds = 0;
    Msg.Cmd.writeFds = 0;

    if( readsds ) {
        Msg.Cmd.readFds       = (uint16_t)readsds->fd_array[0];
    }
    if( writesds ) {
        Msg.Cmd.writeFds      = (uint16_t)writesds->fd_array[0];
    }
    if( NULL == timeout ) {
        Msg.Cmd.tv_sec = 0xffff;
        Msg.Cmd.tv_usec = 0xffff;
    } else {
        if( 0xffff <= timeout->tv_sec ) {
            Msg.Cmd.tv_sec = 0xffff;
        } else {
            Msg.Cmd.tv_sec = (uint16_t)timeout->tv_sec;
        }
        timeout->tv_usec = timeout->tv_usec >> 10;  /*  convert to milliseconds */
        if( 0xffff <= timeout->tv_usec ) {
            Msg.Cmd.tv_usec = 0xffff;
        } else {
            Msg.Cmd.tv_usec = (uint16_t)timeout->tv_usec;
        }
    }

    /* Use Obj to issue the command, if not available try later */
    ObjIdx = (uint8_t)_driver._SlDrvWaitForPoolObj(SELECT_ID, SL_MAX_SOCKETS);

    if (MAX_CONCURRENT_ACTIONS == ObjIdx) {
        return SL_POOL_IS_EMPTY;
    }
    OSI_RET_OK_CHECK(_nonos.sl_LockObjLock(&g_pCB->ProtectionLockObj, NON_OS_LOCK_OBJ_UNLOCK_VALUE, NON_OS_LOCK_OBJ_LOCK_VALUE, SL_OS_WAIT_FOREVER));

    g_pCB->ObjPool[ObjIdx].pRespArgs =  (uint8_t *)&AsyncRsp;

    OSI_RET_OK_CHECK(_nonos.sl_LockObjUnlock(&g_pCB->ProtectionLockObj, NON_OS_LOCK_OBJ_UNLOCK_VALUE));
    /* send the command */
    VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSelectCmdCtrl, &Msg, NULL));

    if(SL_OS_RET_CODE_OK == (int16_t)Msg.Rsp.status) {
        OSI_RET_OK_CHECK(_nonos.sl_SyncObjWait(&g_pCB->ObjPool[ObjIdx].SyncObj, NON_OS_SYNC_OBJ_SIGNAL_VALUE, NON_OS_SYNC_OBJ_CLEAR_VALUE, SL_OS_WAIT_FOREVER));
        Msg.Rsp.status = AsyncRsp.status;

        if(  ((int16_t)Msg.Rsp.status) >= 0 ) {
            if( readsds ) {
                readsds->fd_array[0]  = AsyncRsp.readFds;
            }
            if( writesds ) {
                writesds->fd_array[0] = AsyncRsp.writeFds;
            }
        }
    }

    _driver._SlDrvReleasePoolObj(ObjIdx);
    return (int16_t)Msg.Rsp.status;
}

/*  Select helper functions */
/*******************************************************************************/
/*  SL_FD_SET */
/* ******************************************************************************/
void cc3100_socket::SL_FD_SET(int16_t fd, SlFdSet_t *fdset)
{
    fdset->fd_array[0] |=  (1<< (fd & BSD_SOCKET_ID_MASK));
}
/*******************************************************************************/
/*  SL_FD_CLR */
/*******************************************************************************/
void cc3100_socket::SL_FD_CLR(int16_t fd, SlFdSet_t *fdset)
{
    fdset->fd_array[0] &=  ~(1<< (fd & BSD_SOCKET_ID_MASK));
}
/*******************************************************************************/
/*  SL_FD_ISSET */
/*******************************************************************************/
int16_t  cc3100_socket::SL_FD_ISSET(int16_t fd, SlFdSet_t *fdset)
{
    if( fdset->fd_array[0] & (1<< (fd & BSD_SOCKET_ID_MASK)) ) {
        return 1;
    }
    return 0;
}
/*******************************************************************************/
/*  SL_FD_ZERO */
/*******************************************************************************/
void cc3100_socket::SL_FD_ZERO(SlFdSet_t *fdset)
{
    fdset->fd_array[0] = 0;
}

#endif

}//namespace mbed_cc3100