1.2.2.2 Using The Library

The PLC PHY Sniffer library is an add-on that can be used along with the PLC PHY Driver or the G3 PLC MAC RT Driver. The PHY or MAC RT driver is the one in charge of PLC communications, while the Sniffer is used to encode the packets containing the PLC frames and then send them through a Serial interface.

Following examples illustrate how to use the Sniffer library (which in turn uses the USI service to send the frames to an external tool), to build a Sniffer application. Both G3 and PRIME based examples are provided.

Example implementation of a G3 Sniffer

APP_DATA appData;
    
static uint8_t pPLCDataRxBuffer[APP_PLC_DATA_BUFFER_SIZE];
static uint8_t pPLCDataPIBBuffer[APP_PLC_PIB_BUFFER_SIZE];
static uint8_t pSerialDataBuffer[APP_SERIAL_DATA_BUFFER_SIZE];

static void APP_PLCDataIndCb(DRV_PLC_PHY_RECEPTION_OBJ *indObj, uintptr_t context)
{
    /* Send Received PLC message through USI */
	if (indObj->dataLength) {
        size_t length;

        /* Report RX Symbols */
        appData.plcPIB.id = PLC_ID_RX_PAY_SYMBOLS;
        appData.plcPIB.length = 2;
        DRV_PLC_PHY_PIBGet(appData.drvPl360Handle, &appData.plcPIB);

        SRV_PSNIFFER_SetRxPayloadSymbols(*(uint16_t *)appData.plcPIB.pData);

        /* Add received message */
        length = SRV_PSNIFFER_SerialRxMessage(appData.pSerialData, indObj);
        /* Send through USI */
        SRV_USI_Send_Message(appData.srvUSIHandle, SRV_USI_PROT_ID_SNIFF_G3,
                appData.pSerialData, length);
    }
}

void APP_USIPhyProtocolEventHandler(uint8_t *pData, size_t length)
{
    /* Message received from PLC Tool - USART */
	uint8_t command;

	/* Retrieve Command from received message */
	command = SRV_PSNIFFER_GetCommand(pData);

	switch (command) {
        /* Only TONE_MASK Command expected */
        case SRV_PSNIFFER_CMD_SET_TONE_MASK:
        {
            /* Convert ToneMask from Sniffer Tool to PLC phy layer */
            SRV_PSNIFFER_ConvertToneMask(appData.plcPIB.pData, pData + 1);

            /* Send data to PLC */
            appData.plcPIB.id = PLC_ID_TONE_MASK;
            appData.plcPIB.length = PSNIFFER_CARRIERS_SIZE;
            DRV_PLC_PHY_PIBSet(appData.drvPl360Handle, &appData.plcPIB);

        }
        break;

        default:
            break;
    }
}

void APP_Initialize(void)
{
    /* Place the App state machine in its initial state. */
    appData.state = APP_STATE_INIT;

    /* Initialize PLC objects */
    appData.plcRxObj.pReceivedData = pPLCDataRxBuffer;
    appData.plcPIB.pData = pPLCDataPIBBuffer;
    appData.pSerialData = pSerialDataBuffer;
}

void APP_Tasks(void)
{
    /* Check the application's current state. */
    switch(appData.state)
    {
        /* Application's initial state. */
        case APP_STATE_INIT:
        {
            /* Open PLC driver : Start uploading process */
            appData.drvPl360Handle = DRV_PLC_PHY_Open(DRV_PLC_PHY_INDEX, NULL);

            if (appData.drvPl360Handle != DRV_HANDLE_INVALID)
            {
                /* Set Application to next state */
                appData.state = APP_STATE_REGISTER;
            }
            else
            {
                /* Set Application to ERROR state */
                appData.state = APP_STATE_ERROR;
            }
            break;
        }

        /* Waiting to PLC transceiver be opened and register callback functions */
        case APP_STATE_REGISTER:
        {
            /* Check PLC transceiver */
            if (DRV_PLC_PHY_Status(DRV_PLC_PHY_INDEX) == SYS_STATUS_READY)
            {
                /* Register PLC callback */
                DRV_PLC_PHY_DataIndCallbackRegister(appData.drvPl360Handle,
                        APP_PLCDataIndCb, DRV_PLC_PHY_INDEX);

                /* Open USI Service */
                appData.srvUSIHandle = SRV_USI_Open(SRV_USI_INDEX_0);

                if (appData.srvUSIHandle != DRV_HANDLE_INVALID)
                {
                    /* Set Application to next state */
                    appData.state = APP_STATE_CONFIG_USI;
                }
                else
                {
                    /* Set Application to ERROR state */
                    appData.state = APP_STATE_ERROR;
                }
            }
            break;
        }

        case APP_STATE_CONFIG_USI:
        {
            if (SRV_USI_Status(appData.srvUSIHandle) == SRV_USI_STATUS_CONFIGURED)
            {
                /* Register USI callback */
                SRV_USI_CallbackRegister(appData.srvUSIHandle,
                        SRV_USI_PROT_ID_SNIFF_G3, APP_USIPhyProtocolEventHandler);
                    
                /* Set Application to next state */
                appData.state = APP_STATE_READY;
            }
            break;
        }

        case APP_STATE_READY:
        {
            /* Check USI status in case of USI device has been reset */
            if (SRV_USI_Status(appData.srvUSIHandle) == SRV_USI_STATUS_NOT_CONFIGURED)
            {
                /* Set Application to next state */
                appData.state = APP_STATE_CONFIG_USI;
            }
            break;
        }

        case APP_STATE_ERROR:
        {
            /* Handle error in application's state machine */
            break;
        }

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

Example implementation of a PRIME Sniffer

APP_DATA appData;
    
static uint8_t pPLCDataRxBuffer[APP_PLC_DATA_BUFFER_SIZE];
static uint8_t pPLCDataPIBBuffer[APP_PLC_PIB_BUFFER_SIZE];
static uint8_t pSerialDataBuffer[APP_SERIAL_DATA_BUFFER_SIZE];


static void APP_PLCDataIndCb(DRV_PLC_PHY_RECEPTION_OBJ *indObj, uintptr_t context)
{
    /* Send Received PLC message through USI */
	if (indObj->dataLength) {
        size_t length;
        
        /* Report RX Symbols */
        appData.plcPIB.id = PLC_ID_RX_PAY_SYMBOLS;
        appData.plcPIB.length = 2;
        DRV_PLC_PHY_PIBGet(appData.drvPl360Handle, &appData.plcPIB);

        SRV_PSNIFFER_SetRxPayloadSymbols(*(uint16_t *)appData.plcPIB.pData);

        /* Serialize received message */
        length = SRV_PSNIFFER_SerialRxMessage(appData.pSerialData, indObj);
        /* Send through USI */
        SRV_USI_Send_Message(appData.srvUSIHandle, SRV_USI_PROT_ID_SNIF_PRIME,
                appData.pSerialData, length);
    }
}

void APP_USIPhyProtocolEventHandler(uint8_t *pData, size_t length)
{
    /* Message received from PLC Tool - USART */
	uint8_t command;

	/* Process received message */
	command = SRV_PSNIFFER_GetCommand(pData);

	switch (command) {
        /* Only SET_CHANNEL Command expected */
        case SRV_PSNIFFER_CMD_SET_CHANNEL:
        {
            SRV_PLC_PCOUP_CHANNEL channel;
            
            channel = *(pData + 1);
            
            if ((appData.channel != channel) && (channel >= CHN1) && (channel <= CHN7_CHN8))
            {
                appData.channel = channel;
                
                /* Set channel configuration */
                appData.plcPIB.id = PLC_ID_CHANNEL_CFG;
                appData.plcPIB.length = 1;
                *appData.plcPIB.pData = channel;
                DRV_PLC_PHY_PIBSet(appData.drvPl360Handle, &appData.plcPIB);
                /* Update channel in PSniffer */
                SRV_PSNIFFER_SetPLCChannel(appData.channel);
            }
        }
        break;

        default:
            break;
    }
}

void APP_Initialize(void)
{
    /* Place the App state machine in its initial state. */
    appData.state = APP_STATE_INIT;

    /* Initialize PLC objects */
    appData.plcRxObj.pReceivedData = pPLCDataRxBuffer;
    appData.plcPIB.pData = pPLCDataPIBBuffer;
    appData.pSerialData = pSerialDataBuffer;
    
    /* Init Channel */
    appData.channel = SRV_PCOUP_Get_Default_Channel();
}

void APP_Tasks(void)
{
    /* Check the application's current state. */
    switch(appData.state)
    {
        /* Application's initial state. */
        case APP_STATE_INIT:
        {
            /* Open PLC driver : Start uploading process */
            appData.drvPl360Handle = DRV_PLC_PHY_Open(DRV_PLC_PHY_INDEX, NULL);

            if (appData.drvPl360Handle != DRV_HANDLE_INVALID)
            {
                /* Set Application to next state */
                appData.state = APP_STATE_REGISTER;
            }
            else
            {
                /* Set Application to ERROR state */
                appData.state = APP_STATE_ERROR;
            }
            break;
        }

        /* Waiting to PLC transceiver be opened and register callback functions */
        case APP_STATE_REGISTER:
        {
            /* Check PLC transceiver */
            if (DRV_PLC_PHY_Status(DRV_PLC_PHY_INDEX) == SYS_STATUS_READY)
            {
                /* Register PLC callback */
                DRV_PLC_PHY_DataIndCallbackRegister(appData.drvPl360Handle,
                        APP_PLCDataIndCb, DRV_PLC_PHY_INDEX);

                /* Open USI Service */
                appData.srvUSIHandle = SRV_USI_Open(SRV_USI_INDEX_0);

                if (appData.srvUSIHandle != DRV_HANDLE_INVALID)
                {
                    /* Set Application to next state */
                    appData.state = APP_STATE_CONFIG_USI;
                }
                else
                {
                    /* Set Application to ERROR state */
                    appData.state = APP_STATE_ERROR;
                }
            }
            break;
        }

        case APP_STATE_CONFIG_USI:
        {
            if (SRV_USI_Status(appData.srvUSIHandle) == SRV_USI_STATUS_CONFIGURED)
            {
                /* Register USI callback */
                SRV_USI_CallbackRegister(appData.srvUSIHandle,
                        SRV_USI_PROT_ID_SNIF_PRIME, APP_USIPhyProtocolEventHandler);
                
                /* Set channel configuration */
                appData.plcPIB.id = PLC_ID_CHANNEL_CFG;
                appData.plcPIB.length = 1;
                *appData.plcPIB.pData = appData.channel;
                DRV_PLC_PHY_PIBSet(appData.drvPl360Handle, &appData.plcPIB);
                /* Update channel in PSniffer */
                SRV_PSNIFFER_SetPLCChannel(appData.channel);
                
                appData.plcPIB.id = PLC_ID_NUM_CHANNELS;
                appData.plcPIB.length = 1;
                if (appData.channel > CHN8) 
                {
                    *appData.plcPIB.pData = 2;
                }
                else
                {
                    *appData.plcPIB.pData = 1;
                }
                DRV_PLC_PHY_PIBSet(appData.drvPl360Handle, &appData.plcPIB);
                    
                /* Set Application to next state */
                appData.state = APP_STATE_READY;
            }
            break;
        }

        case APP_STATE_READY:
        {
            /* Check USI status in case of USI device has been reset */
            if (SRV_USI_Status(appData.srvUSIHandle) == SRV_USI_STATUS_NOT_CONFIGURED)
            {
                /* Set Application to next state */
                appData.state = APP_STATE_CONFIG_USI;
            }
            break;
        }

        case APP_STATE_ERROR:
        {
            /* Handle error in application's state machine */
            break;
        }

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