1.1.2.2 Using The Library

The G3 MAC RT library builds on top of an SPI peripheral library (PLIB) to communicate with a PLC transceiver in which G3-PLC lower MAC and PHY layers run.

However, the underlying use of an SPI port is abstracted to the user, and library provides a modem-like interface with data transmission and reception functions and configuration parameters that can be read/written.

Data Service access is done in asynchronous mode, requiring some callbacks to be set in order to let the library provide communication events to the user.

Management Service access is done in synchronous mode, and the different Get/Set functions provide the results as part of the returned/referenced parameters.

Example application to send data through PLC and wait for a response

#include "app_plc.h"
#include "driver/plc/g3MacRt/drv_g3_macrt.h"
#include "service/pcoup/srv_pcoup.h"
#include "service/random/srv_random.h"

typedef enum
{
    /* Application's state machine's initial state. */
    APP_PLC_STATE_INIT=0,
    APP_PLC_STATE_OPEN,
    APP_PLC_STATE_WAITING,
    APP_PLC_STATE_WAITING_TX_CFM,
    APP_PLC_STATE_ERROR,

} APP_PLC_STATES;

APP_PLC_STATES appPlcState;
DRV_HANDLE drvPlcHandle;
MAC_RT_HEADER txHeader;
uint16_t txLength;
uint8_t txBuffer[MAC_RT_DATA_MAX_SIZE];
bool txConfirmed;
bool frameReceived;

static uint8_t APP_PLC_BuildMacHeader ( uint8_t *pFrame, MAC_RT_HEADER *pHeader )
{
    uint8_t *pData;

    pData = pFrame;

    /* Copy Frame Control and Sequence number */
    memcpy(pData, pHeader, 3);
    pData += 3;
    /* Build Header to use MAC_RT_SHORT_ADDRESS mode */
    /* Destination PAN ID */
    *pData++ = (uint8_t)(pHeader->destinationPAN);
    *pData++ = (uint8_t)(pHeader->destinationPAN >> 8);
    /* Destination address */
    *pData++ = (uint8_t)(pHeader->destinationAddress.shortAddress);
    *pData++ = (uint8_t)(pHeader->destinationAddress.shortAddress >> 8);
    /* panIdCompression = 1 -> No Source PAN ID */
    /* Source Address */
    *pData++ = (uint8_t)(pHeader->sourceAddress.shortAddress);
    *pData++ = (uint8_t)(pHeader->sourceAddress.shortAddress >> 8);

    /* Return Header length */
    return (uint8_t)(pData - pFrame);
}

static void APP_PLC_SendData ( uint8_t* pData, uint16_t length )
{
    uint8_t *pFrame;
    uint8_t headerLen;
    
    if (length > MAC_RT_MAX_PAYLOAD_SIZE) {
        return;
    }
    
    pFrame = txBuffer;
    
    /* Build MAC Frame */
    headerLen = APP_PLC_BuildMacHeader(pFrame, &txHeader);
    pFrame += headerLen;
    
    /* Fill Payload */
    memcpy(pFrame, pData, length);
    pFrame += length;

    /* Send MAC Frame */
    txConfirmed = false;
    DRV_G3_MACRT_TxRequest(drvPlcHandle, txBuffer, pFrame - txBuffer);
}

static void APP_PLC_DataCfmCb( MAC_RT_TX_CFM_OBJ *cfmObj )
{
    /* Update flag */
    txConfirmed = true;

    /* Check result */
    if (cfmObj->status == MAC_RT_STATUS_SUCCESS)
    {

    }
}

static void APP_PLC_DataIndCb( uint8_t *pData, uint16_t length )
{
    /* Do whatever with received frame */
    frameReceived = true;
    txLength = length;
}

static void APP_PLC_RxParamsIndCb( MAC_RT_RX_PARAMETERS_OBJ *pParameters )
{
    /* Store Rx Parameters here */
}

void APP_PLC_Initialize ( void )
{
    /* Fill MAC RT Header */
    txHeader.frameControl.frameType = MAC_RT_FRAME_TYPE_DATA;
    txHeader.frameControl.securityEnabled = 0;
    txHeader.frameControl.framePending = 0;
    txHeader.frameControl.ackRequest = 0;
    txHeader.frameControl.panIdCompression = 1;
    txHeader.frameControl.destAddressingMode = MAC_RT_SHORT_ADDRESS;
    txHeader.frameControl.frameVersion = 1;
    txHeader.frameControl.srcAddressingMode = MAC_RT_SHORT_ADDRESS;
    txHeader.sequenceNumber = 0;
    txHeader.destinationPAN = 0x781D;
    txHeader.destinationAddress.addressMode = MAC_RT_SHORT_ADDRESS;
    txHeader.destinationAddress.shortAddress = 0xFFFF;
    txHeader.sourcePAN = 0x781D;
    txHeader.sourceAddress.addressMode = MAC_RT_SHORT_ADDRESS;
    txHeader.sourceAddress.shortAddress = SRV_RANDOM_Get16bits();
    txLength = 100;
    
    /* Set application state */
    appPlcState = APP_PLC_STATE_INIT;
    txConfirmed = false;
    frameReceived = false;
}

void APP_PLC_Tasks ( void )
{   
    /* Check the application's current state. */
    switch ( appPlcState )
    {
        case APP_PLC_STATE_INIT:
        {
            /* Open PLC driver */
            drvPlcHandle = DRV_G3_MACRT_Open(DRV_G3_MACRT_INDEX_0, NULL);

            if (drvPlcHandle != DRV_HANDLE_INVALID)
            {
                appPlcState = APP_PLC_STATE_OPEN;
            }
            else
            {
                appPlcState = APP_PLC_STATE_ERROR;
            }
            break;
        }

        case APP_PLC_STATE_OPEN:
        {
            /* Check PLC transceiver */
            if (DRV_G3_MACRT_Status(DRV_G3_MACRT_INDEX_0) == SYS_STATUS_READY)
            {
                SRV_PLC_PCOUP_BRANCH defaultBranch;

                /* Configure PLC callbacks */
                DRV_G3_MACRT_TxCfmCallbackRegister(drvPlcHandle, APP_PLC_DataCfmCb);
                DRV_G3_MACRT_DataIndCallbackRegister(drvPlcHandle, APP_PLC_DataIndCb);
                DRV_G3_MACRT_RxParamsIndCallbackRegister(drvPlcHandle, APP_PLC_RxParamsIndCb);
                
                /* Apply PLC coupling configuration */
                defaultBranch = SRV_PCOUP_Get_Default_Branch();
                SRV_PCOUP_Set_Config(drvPlcHandle, defaultBranch);
                
                /* Enable PLC Transmission */
                DRV_G3_MACRT_EnableTX(drvPlcHandle, true);
                
                /* Transmit the first frame */
                APP_PLC_SendData(txBuffer, txLength);
                appPlcState = APP_PLC_STATE_WAITING_TX_CFM;
            }
        }
        break;

        case APP_PLC_STATE_WAITING:
        {
            if (frameReceived)
            {
                frameReceived = false;
                /* Send another frame */
                APP_PLC_SendData(txBuffer, txLength);
                appPlcState = APP_PLC_STATE_WAITING_TX_CFM;
            }
            break;
        }

        case APP_PLC_STATE_WAITING_TX_CFM:
        {
            if (txConfirmed)
            {
                txConfirmed = false;
                appPlcState = APP_PLC_STATE_WAITING;
            }
            break;
        }

        /* The default state should never be executed. */
        default:
        {
            /* Handle error in application's state machine. */
            break;
        }
    }
}