1.2.12.2 Using The Library

The SE Queue library is called to initialize a queue, add and remove elements from it and reading elements.

The following example illustrates how the SE Queue service is used by the TCP/IP - G3 ADP/MAC interface.

Example of SE Queue library usage

#include "stack/g3/net/macg3adp/drv_mac_g3adp.h"
#include "drv_mac_g3adp_local.h"
#include "system/sys_time_h2_adapter.h"
#include "tcpip/tcpip_mac_object.h"
#include "service/queue/srv_queue.h"
#include "stack/g3/adaptation/adp.h"
#include "stack/g3/mac/mac_wrapper/mac_wrapper_defs.h"

#define DRV_MAC_G3ADP_PACKET_TX_QUEUE_LIMIT         5
#define DRV_MAC_G3ADP_PACKET_RX_QUEUE_LIMIT         5

typedef struct
{
    SRV_QUEUE_ELEMENT       queueElement;      // queue element
    TCPIP_MAC_PACKET *      pMacPacket;        // pointer to the TCPIP MAC packet
    bool                    inUse;             // Flag to indicate if the element is being used in a queue
} DRV_G3ADP_MAC_QUEUE_DATA;

static DRV_G3ADP_MAC_DRIVER _g3adp_mac_drv_dcpt;

/******************************************************************************
 * G3 ADP MAC local functions
 ******************************************************************************/
static DRV_G3ADP_MAC_QUEUE_DATA * _DRV_G3ADP_MAC_GetFreeQueueData(DRV_G3ADP_MAC_QUEUE_DATA *dataPool,
        uint16_t dataLen)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;
    DRV_G3ADP_MAC_QUEUE_DATA *ptrDataPool = dataPool;
    uint8_t index;
    uint8_t poolSize = DRV_MAC_G3ADP_PACKET_TX_QUEUE_LIMIT;

    if (dataPool == _rxDataPool)
    {
        poolSize = DRV_MAC_G3ADP_PACKET_RX_QUEUE_LIMIT;
    }

    for (index = 0; index < poolSize; index++, ptrDataPool++)
    {
        if (ptrDataPool->inUse == false)
        {
            if (dataLen)
            {
                // Dynamically allocate MAC Packet
                ptrDataPool->pMacPacket = pMacDrv->g3AdpMacData.pktAllocF(sizeof(TCPIP_MAC_PACKET),
                        dataLen, TCPIP_MAC_PKT_FLAG_CAST_DISABLED);

                if (ptrDataPool->pMacPacket == NULL)
                {
                    return NULL;
                }
            }

            ptrDataPool->inUse = true;
            return ptrDataPool;
        }
    }

    return NULL;
}

static DRV_G3ADP_MAC_QUEUE_DATA * _DRV_G3ADP_MAC_GetQueueDataFromMACPacket(DRV_G3ADP_MAC_QUEUE_DATA *dataPool,
        TCPIP_MAC_PACKET * pMacPacket)
{
    DRV_G3ADP_MAC_QUEUE_DATA *ptrDataPool = dataPool;
    uint8_t index;
    uint8_t poolSize = DRV_MAC_G3ADP_PACKET_TX_QUEUE_LIMIT;

    if (dataPool == _rxDataPool)
    {
        poolSize = DRV_MAC_G3ADP_PACKET_RX_QUEUE_LIMIT;
    }

    for (index = 0; index < poolSize; index++, ptrDataPool++)
    {
        if ((ptrDataPool->inUse == true) && (ptrDataPool->pMacPacket == pMacPacket))
        {
            return ptrDataPool;
        }
    }

    return NULL;
}

static bool _DRV_G3ADP_MAC_PutFreeQueueData(DRV_G3ADP_MAC_QUEUE_DATA *dataPool,
        DRV_G3ADP_MAC_QUEUE_DATA *queuedData, bool pktFreeF)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;
    DRV_G3ADP_MAC_QUEUE_DATA *ptrDataPool = dataPool;
    uint8_t index;
    uint8_t poolSize = DRV_MAC_G3ADP_PACKET_TX_QUEUE_LIMIT;

    if (dataPool == _rxDataPool)
    {
        poolSize = DRV_MAC_G3ADP_PACKET_RX_QUEUE_LIMIT;
    }

    for (index = 0; index < poolSize; index++, ptrDataPool++)
    {
        if (ptrDataPool == queuedData)
        {
            if (pktFreeF && (pMacDrv->g3AdpMacData.pktFreeF))
            {
                // Free memory
                pMacDrv->g3AdpMacData.pktFreeF(ptrDataPool->pMacPacket);
            }
            ptrDataPool->inUse = false;
            return true;
        }
    }

    return false;
}

static void _DRV_G3ADP_MAC_RxMacFreePacket(TCPIP_MAC_PACKET * pMacPacket, const void * param)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = (DRV_G3ADP_MAC_DRIVER *) param;

    if (pMacPacket &&  pMacPacket->pDSeg
            &&  (pMacPacket->pDSeg->segFlags & TCPIP_MAC_SEG_FLAG_ACK_REQUIRED))
    {
        DRV_G3ADP_MAC_QUEUE_DATA * rxQueueData =_DRV_G3ADP_MAC_GetQueueDataFromMACPacket(_rxDataPool, pMacPacket);

        if (rxQueueData != NULL)
        {
            _DRV_G3ADP_MAC_PutFreeQueueData(_rxDataPool, rxQueueData, true);
            // Update RX statistics
            pMacDrv->g3AdpMacData.rxStat.nRxPendBuffers--;
        }
    }
}

/******************************************************************************
 * G3 ADP MAC local callbacks
 ******************************************************************************/
void _DRV_G3ADP_MAC_AdpDataCfmCallback(ADP_DATA_CFM_PARAMS* pDataCfm)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;
    DRV_G3ADP_MAC_QUEUE_DATA * txQueueData;

    if (pMacDrv->g3AdpMacData._macFlags._open)
    {
        TCPIP_MAC_PACKET * pMacPacket = (TCPIP_MAC_PACKET *)pDataCfm->nsduHandle;
        TCPIP_MAC_EVENT *event = &pMacDrv->g3AdpMacData.pendingEvents;
        ADP_RESULT result = (ADP_RESULT)pDataCfm->status;

        switch (result)
        {
            case G3_SUCCESS:
                pMacPacket->ackRes = TCPIP_MAC_PKT_ACK_TX_OK;
                pMacDrv->g3AdpMacData.txStat.nTxOkPackets++;
                *event |= TCPIP_MAC_EV_TX_DONE;
                break;

            case G3_INVALID_REQUEST:
                pMacPacket->ackRes = TCPIP_MAC_PKT_ACK_NET_DOWN;
                pMacDrv->g3AdpMacData.txStat.nTxErrorPackets++;
                *event |= TCPIP_MAC_EV_TX_BUSERR;
                break;

            case G3_INVALID_IPV6_FRAME:
                pMacPacket->ackRes = TCPIP_MAC_PKT_ACK_IP_REJECT_ERR;
                pMacDrv->g3AdpMacData.txStat.nTxErrorPackets++;
                *event |= TCPIP_MAC_EV_TX_BUSERR;
                break;

            case G3_ROUTE_ERROR:
                pMacPacket->ackRes = TCPIP_MAC_PKT_ACK_LINK_DOWN;
                pMacDrv->g3AdpMacData.txStat.nTxErrorPackets++;
                *event |= TCPIP_MAC_EV_TX_BUSERR;
                break;

            case G3_NO_BUFFERS:
                pMacPacket->ackRes = TCPIP_MAC_PKT_ACK_BUFFER_ERR;
                pMacDrv->g3AdpMacData.txStat.nTxErrorPackets++;
                *event |= TCPIP_MAC_EV_TX_BUSERR;
                break;

            default:
                pMacPacket->ackRes = TCPIP_MAC_PKT_ACK_MAC_REJECT_ERR;
                pMacDrv->g3AdpMacData.txStat.nTxErrorPackets++;
                *event |= TCPIP_MAC_EV_TX_ABORT;
                break;

        }

        pMacPacket->pktFlags &= ~TCPIP_MAC_PKT_FLAG_QUEUED;

        txQueueData = _DRV_G3ADP_MAC_GetQueueDataFromMACPacket(_txDataPool, pMacPacket);
        _DRV_G3ADP_MAC_PutFreeQueueData(_txDataPool, txQueueData, 0);
        // Update TX statistics
        pMacDrv->g3AdpMacData.txStat.nTxPendBuffers--;

        if (pMacPacket->ackFunc)
        {
            pMacPacket->ackFunc(pMacPacket, pMacPacket->ackParam);
        }

    }
}

void _DRV_G3ADP_MAC_AdpDataIndCallback(ADP_DATA_IND_PARAMS* pDataInd)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;

    if (pMacDrv->g3AdpMacData._macFlags._open)
    {
        DRV_G3ADP_MAC_QUEUE_DATA * rxQueueData;
        TCPIP_MAC_PACKET * pMacPacket;
        TCPIP_MAC_DATA_SEGMENT * pDSeg;

        // Get a Free Queue Element from the RX Queue Data Pool
        rxQueueData = (DRV_G3ADP_MAC_QUEUE_DATA *)_DRV_G3ADP_MAC_GetFreeQueueData(_rxDataPool,
                pDataInd->nsduLength);
        if (rxQueueData == NULL)
        {
            pMacDrv->g3AdpMacData.rxStat.nRxBuffNotAvailable++;
            return;
        }

        pMacPacket = rxQueueData->pMacPacket;
        pDSeg = pMacPacket->pDSeg;

        // Set pMacLayer and pNetLayer
        pMacPacket->pMacLayer = pDSeg->segLoad;
        pMacPacket->pNetLayer = pMacPacket->pMacLayer + sizeof(TCPIP_MAC_ETHERNET_HEADER);

        // Set Ethernet Header Type - TCPIP_ETHER_TYPE_IPV6
        TCPIP_MAC_ETHERNET_HEADER* pMacHdr = (TCPIP_MAC_ETHERNET_HEADER*)pMacPacket->pMacLayer;
        pMacHdr->Type = TCPIP_Helper_htons(0x86DDu);

        // Copy data payload to Net Layer Payload
        memcpy(pMacPacket->pNetLayer, pDataInd->pNsdu, pDataInd->nsduLength);
        pDSeg->segLen = pDataInd->nsduLength + sizeof(TCPIP_MAC_ETHERNET_HEADER);
        pDSeg->segFlags |= TCPIP_MAC_SEG_FLAG_ACK_REQUIRED; // allow rxMacPacketAck entry

        // Add timestamp
        pMacPacket->tStamp = SYS_TMR_TickCountGet();
        // just one single packet
        pMacPacket->next = NULL;
        // setup the packet acknowledgment for later use;
        pMacPacket->ackFunc = _DRV_G3ADP_MAC_RxMacFreePacket;
        pMacPacket->ackParam = pMacDrv;
        // Update Packet flags
        pMacPacket->pktFlags |= TCPIP_MAC_PKT_FLAG_QUEUED;
        pDSeg->next = NULL;

        // Append ADP packets to the ADP RX queue
        SRV_QUEUE_Append(&pMacDrv->g3AdpMacData.adpRxQueue, (SRV_QUEUE_ELEMENT *)rxQueueData);
        rxQueueData->inUse = true;

        // Update RX statistics
        pMacDrv->g3AdpMacData.rxStat.nRxSchedBuffers++;
        pMacDrv->g3AdpMacData.rxStat.nRxPendBuffers++;

        // Set RX triggered events: A receive packet is pending
        pMacDrv->g3AdpMacData.pendingEvents |= TCPIP_MAC_EV_RX_DONE;

        if (pMacDrv->g3AdpMacData.eventF)
        {
            pMacDrv->g3AdpMacData.eventF(TCPIP_MAC_EV_RX_DONE, pMacDrv->g3AdpMacData.eventParam);
        }
    }
}

/******************************************************************************
 * G3 ADP MAC interface
 ******************************************************************************/
SYS_MODULE_OBJ DRV_G3ADP_MAC_Initialize(const SYS_MODULE_INDEX index, const SYS_MODULE_INIT * const init)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv;
    const TCPIP_MAC_MODULE_CTRL* macControl = ((TCPIP_MAC_INIT*)init)->macControl;

    if (index != TCPIP_MODULE_MAC_PIC32CXMT)
    {
        return SYS_MODULE_OBJ_INVALID;      // single instance
    }

    pMacDrv = &_g3adp_mac_drv_dcpt;

    if (pMacDrv->g3AdpMacData._macFlags._init != 0)
    {   // already initialized
        return (SYS_MODULE_OBJ)pMacDrv;
    }

    if (pMacDrv->g3AdpMacData._macFlags._open != 0)
    {
        return SYS_MODULE_OBJ_INVALID;     // client already connected
    }

    // Init G3 Adp Mac data
    memset(&pMacDrv->g3AdpMacData, 0x0, sizeof(pMacDrv->g3AdpMacData));

    // use initialization data
    pMacDrv->g3AdpMacData.allocH = macControl->memH;
    pMacDrv->g3AdpMacData.callocF = macControl->callocF;
    pMacDrv->g3AdpMacData.freeF = macControl->freeF;
    pMacDrv->g3AdpMacData.pktAllocF = macControl->pktAllocF;
    pMacDrv->g3AdpMacData.pktFreeF = macControl->pktFreeF;
    pMacDrv->g3AdpMacData.pktAckF = macControl->pktAckF;

    // use events data
    pMacDrv->g3AdpMacData.eventF = macControl->eventF;
    pMacDrv->g3AdpMacData.eventParam = macControl->eventParam;

    pMacDrv->g3AdpMacData.controlFlags = macControl->controlFlags;

    // Init G3 ADP MAC Tx/Rx queues
    SRV_QUEUE_Init(&pMacDrv->g3AdpMacData.adpTxQueue, DRV_MAC_G3ADP_PACKET_TX_QUEUE_LIMIT, SRV_QUEUE_TYPE_PRIORITY);
    SRV_QUEUE_Init(&pMacDrv->g3AdpMacData.adpRxQueue, DRV_MAC_G3ADP_PACKET_RX_QUEUE_LIMIT, SRV_QUEUE_TYPE_SINGLE);
    memset(_txDataPool, 0, sizeof(_txDataPool));
    memset(_rxDataPool, 0, sizeof(_rxDataPool));

    pMacDrv->g3AdpMacData._macFlags._init = 1;
    pMacDrv->g3AdpMacData._macFlags._open = 0;
    pMacDrv->g3AdpMacData._macFlags._linkPresent = 0;
    pMacDrv->g3AdpMacData.sysStat = SYS_STATUS_BUSY;

    return (SYS_MODULE_OBJ)pMacDrv;
}

TCPIP_MAC_RES DRV_G3ADP_MAC_PacketTx(DRV_HANDLE hMac, TCPIP_MAC_PACKET * ptrPacket)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;

    if (hMac != (DRV_HANDLE)pMacDrv)
    {
        return TCPIP_MAC_RES_OP_ERR;
    }

    if (pMacDrv->g3AdpMacData._macFlags._open == 0)
    {
        return TCPIP_MAC_RES_INIT_FAIL;
    }

    // new packet for transmission
    while (ptrPacket)
    {
        DRV_G3ADP_MAC_QUEUE_DATA * txQueueData;

        // Get a Free Queue Element from the TX Queue Data Pool
        txQueueData = (DRV_G3ADP_MAC_QUEUE_DATA *)_DRV_G3ADP_MAC_GetFreeQueueData(_txDataPool, 0);
        if (txQueueData == NULL)
        {
            pMacDrv->g3AdpMacData.txStat.nTxQueueFull++;
            return TCPIP_MAC_RES_QUEUE_TX_FULL;
        }

        txQueueData->pMacPacket = ptrPacket;

        // Append ADP packets to the ADP TX queue
        SRV_QUEUE_Append_With_Priority(&pMacDrv->g3AdpMacData.adpTxQueue, (ptrPacket->pktPriority > 0),
                (SRV_QUEUE_ELEMENT *)txQueueData);

        ptrPacket->pktFlags |= TCPIP_MAC_PKT_FLAG_QUEUED;
        pMacDrv->g3AdpMacData.txStat.nTxPendBuffers++;

        if (pMacDrv->g3AdpMacData.eventF)
        {
            pMacDrv->g3AdpMacData.eventF(TCPIP_MAC_EV_TX_DONE, pMacDrv->g3AdpMacData.eventParam);
        }

        ptrPacket = ptrPacket->next;
    }

    return TCPIP_MAC_RES_OK;
}

TCPIP_MAC_PACKET* DRV_G3ADP_MAC_PacketRx (DRV_HANDLE hMac, TCPIP_MAC_RES* pRes, TCPIP_MAC_PACKET_RX_STAT* pPktStat)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;
    TCPIP_MAC_PACKET * pRxPkt = NULL;
    DRV_G3ADP_MAC_QUEUE_DATA * rxQueueData;
    TCPIP_MAC_RES mRes = TCPIP_MAC_RES_OK;

    if (hMac != (DRV_HANDLE)pMacDrv)
    {
        return 0;
    }

    rxQueueData = (DRV_G3ADP_MAC_QUEUE_DATA *)SRV_QUEUE_Read_Or_Remove(&pMacDrv->g3AdpMacData.adpRxQueue,
            SRV_QUEUE_MODE_REMOVE, SRV_QUEUE_POSITION_HEAD);
    if (rxQueueData == NULL)
    {
        return 0;
    }
    else
    {
        // Update RX statistics
        pMacDrv->g3AdpMacData.rxStat.nRxSchedBuffers--;

        pRxPkt = rxQueueData->pMacPacket;

        if (pRxPkt == NULL)
        {
            mRes = TCPIP_MAC_RES_INTERNAL_ERR;
            pMacDrv->g3AdpMacData.rxStat.nRxErrorPackets++;
        }
    }

    if (pRes)
    {
        *pRes = mRes;
    }

    // Update RX statistics
    pMacDrv->g3AdpMacData.rxStat.nRxOkPackets++;

    return pRxPkt;
}

TCPIP_MAC_RES DRV_G3ADP_MAC_Process(DRV_HANDLE hMac)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;

    if (hMac != (DRV_HANDLE)pMacDrv)
    {
        return TCPIP_MAC_RES_OP_ERR;
    }

    if (pMacDrv->g3AdpMacData._macFlags._open == 0)
    {
        return TCPIP_MAC_RES_OP_ERR;
    }

    // G3 ADP TX Process
    DRV_G3ADP_MAC_QUEUE_DATA * txQueueData = (DRV_G3ADP_MAC_QUEUE_DATA *)SRV_QUEUE_Read_Or_Remove(&pMacDrv->g3AdpMacData.adpTxQueue,
        SRV_QUEUE_MODE_REMOVE, SRV_QUEUE_POSITION_HEAD);
    while (txQueueData != NULL)
    {
        // Send packets to G3 ADP
        TCPIP_MAC_PACKET * ptrPacket = txQueueData->pMacPacket;
        if (ptrPacket->pNetLayer)
        {
            IPV6_HEADER *ipv6Pkt = (IPV6_HEADER *)ptrPacket->pNetLayer;
            uint16_t length = sizeof(IPV6_HEADER) + TCPIP_Helper_htons(ipv6Pkt->PayloadLength);
            ADP_DataRequest(length, (const uint8_t *)ipv6Pkt, (uint32_t)ptrPacket, true, (ptrPacket->pktPriority > 0));
        }

        // Get next Queued Data
        txQueueData = (DRV_G3ADP_MAC_QUEUE_DATA *)SRV_QUEUE_Read_Or_Remove(&pMacDrv->g3AdpMacData.adpTxQueue,
            SRV_QUEUE_MODE_REMOVE, SRV_QUEUE_POSITION_HEAD);
    }

    return TCPIP_MAC_RES_OK;
}

TCPIP_MAC_RES DRV_G3ADP_MAC_ParametersGet(DRV_HANDLE hMac, TCPIP_MAC_PARAMETERS* pMacParams)
{
    DRV_G3ADP_MAC_DRIVER * pMacDrv = &_g3adp_mac_drv_dcpt;

    if (hMac != (DRV_HANDLE)pMacDrv)
    {
        return TCPIP_MAC_RES_OP_ERR;
    }

    if (pMacDrv->g3AdpMacData.sysStat == SYS_STATUS_READY)
    {
        if (pMacParams)
        {
            ADP_MAC_GET_CFM_PARAMS getConfirm;
            ADP_DATA_NOTIFICATIONS adpDataNot;

            // Set ADP Data Notifications
            adpDataNot.dataConfirm = _DRV_G3ADP_MAC_AdpDataCfmCallback;
            adpDataNot.dataIndication = _DRV_G3ADP_MAC_AdpDataIndCallback;
            ADP_SetDataNotifications(&adpDataNot);

            // Get MAC address from ADP Extended Address
            ADP_MacGetRequestSync(MAC_WRP_PIB_MANUF_EXTENDED_ADDRESS, 0, &getConfirm);
            memcpy(&pMacParams->ifPhyAddress, &getConfirm.attributeValue[2],
                    sizeof(pMacParams->ifPhyAddress));

            pMacParams->processFlags = (TCPIP_MAC_PROCESS_FLAG_RX | TCPIP_MAC_PROCESS_FLAG_TX);
            pMacParams->macType = TCPIP_MAC_TYPE_G3ADP;
            pMacParams->linkMtu = TCPIP_MAC_LINK_MTU_G3ADP;
            pMacParams->checksumOffloadRx = TCPIP_MAC_CHECKSUM_NONE;
            pMacParams->checksumOffloadTx = TCPIP_MAC_CHECKSUM_NONE;
            pMacParams->macTxPrioNum = 2;
            pMacParams->macRxPrioNum = 1;
        }

        return TCPIP_MAC_RES_OK;
    }

    return TCPIP_MAC_RES_IS_BUSY;
}