Jump to main content

# 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;
    }

Rev: G