1.1.1.2 Using The Library

The PLC PHY library builds on top of an SPI peripheral library (PLIB) to communicate with a PLC transceiver in which G3-PLC or PRIME PHY layer 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 (Transmission Confirm and Receive Indication) to the user.

Management Service access is done in synchronous mode, and the 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/phy/drv_plc_phy.h"
#include "service/pcoup/srv_pcoup.h"

/* The maximum length depends on the protocol (G3-PLC/PRIME) and the modulation */
#define APP_PLC_BUFFER_SIZE 256

/* Time between messages in microseconds */
#define APP_PLC_TIME_BETWEEN_MSG 5000

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;
DRV_PLC_PHY_TRANSMISSION_OBJ plcPhyTx;
uint8_t txBuffer[APP_PLC_BUFFER_SIZE];
bool txConfirmed;
bool frameReceived;

static void APP_PLC_DataCfmCb(DRV_PLC_PHY_TRANSMISSION_CFM_OBJ *cfmObj, uintptr_t context )
{
    /* Update flag */
    txConfirmed = true;

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

    }
}

static void APP_PLC_DataIndCb( DRV_PLC_PHY_RECEPTION_OBJ *indObj, uintptr_t context )
{
    /* Do whatever with received frame */
    frameReceived = true;

    /* Copy parameters and data to respond with a new transmission */
    memcpy(txBuffer, indObj->pReceivedData, indObj->dataLength);
    plcPhyTx.dataLength = indObj->dataLength;
    plcPhyTx.modType = indObj->modType;
    plcPhyTx.modScheme = indObj->modScheme;
    plcPhyTx.delimiterType = indObj->delimiterType;

    /* Set TX time based on RX time (absolute time mode) */
    plcPhyTx.timeIni = indObj->timeEnd + APP_PLC_TIME_BETWEEN_MSG;
    plcPhyTx.mode = TX_MODE_FORCED | TX_MODE_ABSOLUTE;
}

void APP_PLC_Initialize ( void )
{
    /* Initialize PLC transmission parameters structure (G3-PLC) */
    plcPhyTx.pTransmitData = txBuffer;
    plcPhyTx.dataLength = 100;
    plcPhyTx.timeIni = 0;
    plcPhyTx.mode = TX_MODE_FORCED | TX_MODE_RELATIVE;
    plcPhyTx.attenuation = 0;
    plcPhyTx.rs2Blocks = 0;
    plcPhyTx.modType = MOD_TYPE_BPSK;
    plcPhyTx.modScheme = MOD_SCHEME_DIFFERENTIAL;
    plcPhyTx.delimiterType = DT_SOF_NO_RESP;
    
    /* Initialize 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_PLC_PHY_Open(DRV_PLC_PHY_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 driver status */
            if (DRV_PLC_PHY_Status(DRV_PLC_PHY_INDEX_0) == SYS_STATUS_READY)
            {
                SRV_PLC_PCOUP_BRANCH defaultBranch;
                uint8_t phyBand;

                /* Configure PLC callbacks */
                DRV_PLC_PHY_DataCfmCallbackRegister(drvPlcHandle, APP_PLC_DataCfmCb, NULL);
                DRV_PLC_PHY_DataIndCallbackRegister(drvPlcHandle, APP_PLC_DataIndCb, NULL);
                
                /* Apply PLC coupling configuration */
                defaultBranch = SRV_PCOUP_Get_Default_Branch();
                SRV_PCOUP_Set_Config(drvPlcHandle, defaultBranch);

                /* Set Tone Map depending on PHY band (G3-PLC) */
                phyBand = SRV_PCOUP_Get_Phy_Band(defaultBranch);
                switch (phyBand)
                {
                    case G3_CEN_A:
                        plcPhyTx.toneMap[0] = 0x3F;
                        plcPhyTx.toneMap[1] = 0x00;
                        plcPhyTx.toneMap[2] = 0x00;
                        break;
                    
                    case G3_CEN_B:
                        plcPhyTx.toneMap[0] = 0x0F;
                        plcPhyTx.toneMap[1] = 0x00;
                        plcPhyTx.toneMap[2] = 0x00;
                        break;
                    
                    case G3_FCC:
                        plcPhyTx.toneMap[0] = 0xFF;
                        plcPhyTx.toneMap[1] = 0xFF;
                        plcPhyTx.toneMap[2] = 0xFF;
                        break;
                    
                    case G3_ARIB:
                        plcPhyTx.toneMap[0] = 0x03;
                        plcPhyTx.toneMap[1] = 0xFF;
                        plcPhyTx.toneMap[2] = 0xFF;
                        break;

                    default:
                        break;
                }

                /* Enable PLC Transmission */
                DRV_PLC_PHY_EnableTX(drvPlcHandle, true);
                
                /* Transmit the first frame */
                DRV_PLC_PHY_Send(drvPlcHandle, &plcPhyTx);
                appPlcState = APP_PLC_STATE_WAITING_TX_CFM;
            }
        }
        break;

        case APP_PLC_STATE_WAITING:
        {
            if (frameReceived)
            {
                frameReceived = false;
                /* Send another frame */
                DRV_PLC_PHY_Send(drvPlcHandle, &plcPhyTx);
                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;
        }
    }
}