1.5.1.2 Transmission

In the MAC-RT PLC & Go application, to transmit a message it is only needed to call the function APP_PLC_SendData(), passing as parameters the pointer to the data buffer and the data length. The data buffer corresponds with the characters received through the console.

The G3-PLC MAC-RT driver sets everything concerning specific implementation for G3-PLC respecting the MAC 802.15.4 frame format. Thus, any message transmitted by the G3-PLC MAC-RT module must be a standard MAC 802.15.4 frame where the MAC header configures the parameters in the transmission at MAC level. The standard MAC 802.15.4 frame check sequence (FCS, CRC) is also calculated by the G3-PLC MAC-RT driver.

The MAC-RT PLC & Go application configures the default values of the MAC 802.15.4 header frame, updating the contents of the corresponding structure MAC_RT_HEADER (defined in drv_g3_macrt_comm.h file), during the initialization stage in the function APP_PLC_SetInitialConfiguration. Furthermore, the function APP_PLC_SetSourceAddress allows to set the source address (own short address), the function APP_PLC_SetDestinationAddress allows to set the destination address (unicast or broadcast short address) and the function APP_PLC_SetPANID allows to set the PAN ID.
static void APP_PLC_SetInitialConfiguration ( void )
{
    /* Apply PLC coupling configuration */
    SRV_PCOUP_Set_Config(appPlc.drvPlcHandle, appPlc.couplingBranch);

    /* Force Transmission to VLO mode by default in order to maximize signal level in any case */
    /* Disable auto-detect mode */
    appPlc.plcPIB.pib = MAC_RT_PIB_MANUF_PHY_PARAM;
    appPlc.plcPIB.index = PHY_PIB_CFG_AUTODETECT_IMPEDANCE;
    appPlc.plcPIB.length = 1;
    appPlc.plcPIB.pData[0] = 0;
    DRV_G3_MACRT_PIBSet(appPlc.drvPlcHandle, &appPlc.plcPIB);

    /* Set VLO mode */
    appPlc.plcPIB.index = PHY_PIB_CFG_IMPEDANCE;
    appPlc.plcPIB.length = 1;
    appPlc.plcPIB.pData[0] = 2;
    DRV_G3_MACRT_PIBSet(appPlc.drvPlcHandle, &appPlc.plcPIB);

    /* Get PLC PHY version */
    appPlc.plcPIB.index = PHY_PIB_VERSION_NUM;
    appPlc.plcPIB.length = 4;
    DRV_G3_MACRT_PIBGet(appPlc.drvPlcHandle, &appPlc.plcPIB);
    memcpy((uint8_t *)&appPlc.phyVersion, appPlc.plcPIB.pData, 4);
    
    /* Fill MAC RT Header */
    appPlcTx.txHeader.frameControl.frameType = MAC_RT_FRAME_TYPE_DATA;
    appPlcTx.txHeader.frameControl.securityEnabled = 0;
    appPlcTx.txHeader.frameControl.framePending = 0;
    appPlcTx.txHeader.frameControl.ackRequest = 0; // No en Broadcast
    appPlcTx.txHeader.frameControl.frameVersion = 1;
    appPlcTx.txHeader.sequenceNumber = 0;
    
    /* Set PAN_ID */
    APP_PLC_SetPANID(CONF_PAN_ID);
    
    /* Set Addresses */
    APP_PLC_SetDestinationAddress(MAC_RT_SHORT_ADDRESS_BROADCAST);
    APP_PLC_SetSourceAddress((uint16_t)TRNG_ReadData());

    if (appPlc.staticNotchingEnable)
    {
        /* Set Tone Mask (Static Notching) */
        appPlc.plcPIB.pib = MAC_RT_PIB_TONE_MASK;
        appPlc.plcPIB.index = 0;
        appPlc.plcPIB.length = sizeof(MAC_RT_TONE_MASK);
        memcpy(appPlc.plcPIB.pData, appPlcToneMask.toneMask, sizeof(MAC_RT_TONE_MASK));
        DRV_G3_MACRT_PIBSet(appPlc.drvPlcHandle, &appPlc.plcPIB);
    }
}

void APP_PLC_SetSourceAddress ( uint16_t address )
{
    /* Set Short Address in TX header */
    appPlcTx.txHeader.frameControl.srcAddressingMode = MAC_RT_SHORT_ADDRESS;
    appPlcTx.txHeader.sourceAddress.addressMode = MAC_RT_SHORT_ADDRESS;
    appPlcTx.txHeader.sourceAddress.shortAddress = address;
    
    /* Set Short Address in G3 MAC RT device */
    appPlc.plcPIB.pib = MAC_RT_PIB_SHORT_ADDRESS;
    appPlc.plcPIB.index = 0;
    appPlc.plcPIB.length = 2;
    memcpy(appPlc.plcPIB.pData, (uint8_t *)&address, 2);
    DRV_G3_MACRT_PIBSet(appPlc.drvPlcHandle, &appPlc.plcPIB);
}

void APP_PLC_SetDestinationAddress ( uint16_t address )
{
    /* Set Short Address in TX header */
    appPlcTx.txHeader.frameControl.destAddressingMode = MAC_RT_SHORT_ADDRESS;
    appPlcTx.txHeader.destinationAddress.addressMode = MAC_RT_SHORT_ADDRESS;
    appPlcTx.txHeader.destinationAddress.shortAddress = address;
}

void APP_PLC_SetPANID ( uint16_t panid )
{
    /* Set Short Address in TX header */
    appPlcTx.txHeader.frameControl.panIdCompression = 1;
    appPlcTx.txHeader.destinationPAN = panid;
    appPlcTx.txHeader.sourcePAN = panid;
    
    /* Set Short Address in G3 MAC RT device */
    appPlc.plcPIB.pib = MAC_RT_PIB_PAN_ID;
    appPlc.plcPIB.index = 0;
    appPlc.plcPIB.length = 2;
    memcpy(appPlc.plcPIB.pData, (uint8_t *)&panid, 2);
    DRV_G3_MACRT_PIBSet(appPlc.drvPlcHandle, &appPlc.plcPIB);
}
Once the transmission is configured, the function APP_PLC_SendData prepares the data to be sent through PLC, storing the MAC header and the data in the transmission buffer (appPlcTxFrameBuffer). The function APP_PLC_BuildMacRTHeader is used to build the MAC header and store it in the transmission buffer. When all the information is in the transmission buffer, the function DRV_G3_MACRT_TxRequest() is called to request the transmission of the PLC message.
static uint8_t APP_PLC_BuildMacRTHeader ( 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);
}

bool APP_PLC_SendData ( uint8_t* pData, uint16_t length )
{
    if (appPlc.state == APP_PLC_STATE_WAITING)
    {
        if (appPlc.pvddMonTxEnable)
        {
            uint8_t *pFrame;
            uint8_t headerLen;
            
            if (length > MAC_RT_MAX_PAYLOAD_SIZE) {
                return false;
            }
            
            appPlc.plcTxState = APP_PLC_TX_STATE_WAIT_TX_CFM;
            
            pFrame = appPlcTx.pTxFrame;
            
            /* Build MAC RT Frame */
            headerLen = APP_PLC_BuildMacRTHeader(pFrame, &appPlcTx.txHeader);
            pFrame += headerLen;
            
            /* Fill Payload */
            memcpy(pFrame, pData, length);
            pFrame += length;

            /* Send MAC RT Frame */
            DRV_G3_MACRT_TxRequest(appPlc.drvPlcHandle, appPlcTx.pTxFrame, 
                    pFrame - appPlcTx.pTxFrame);

            /* Set PLC state */
            if (appPlc.plcTxState == APP_PLC_TX_STATE_WAIT_TX_CFM)
            {
                appPlc.state = APP_PLC_STATE_WAITING_TX_CFM;
                return true;
            }
        }
    }
    
    return false;
}

Once the G3-PLC MAC-RT finishes the PLC transmission (successfully or not), a transmission data confirm event is triggered indicating the result of the transmission. This event is managed by the APP_PLC_DataCfmCb callback function. This callback receives as parameter a data structure of type MAC_RT_TX_CFM_OBJ.

If some specific behavior (MAC or PHY) needs to be modified (like force the modulation, force a Tone Map or modify the power transmission) or obtained, it must be done through get/set PIBs primitives (DRV_G3_MACRT_PIBGet/DRV_G3_MACRT_PIBSet). The PIB list are detailed by the enumeration type definitions MAC_RT_PIB and MAC_RT_PHY_PIB.

  1. Structure MAC_RT_HEADER and the corresponding elements
    // *****************************************************************************
    /* G3-PLC Frame Control information
       Summary
        This struct includes information related to frame control
       Remarks:
        For more information, please refer to G3-PLC Specification    
    */
    typedef struct {
        /* Frame Type */
        uint16_t frameType : 3;
        /* Security Enable */
        uint16_t securityEnabled : 1;
        /* Frame pending */
        uint16_t framePending : 1;
        /* Ack Request */
        uint16_t ackRequest : 1;
        /* PAN ID Compression */
        uint16_t panIdCompression : 1;
        /* Reserved */
        uint16_t reserved : 3;
        /* Destination Addressing Mode */
        uint16_t destAddressingMode : 2;
        /* Frame Version  */
        uint16_t frameVersion : 2;
        /* Source Addressing Mode */
        uint16_t srcAddressingMode : 2;  
    } MAC_RT_FRAME_CONTROL;
    
    // *****************************************************************************
    /* G3-PLC MAC RT Auxiliary Security Header
       Summary
        This struct includes information related to auxiliary security header
       Remarks:
        For more information, please refer to G3-PLC Specification
    */
    typedef struct {
        /* Security Level */
        uint8_t securityLevel : 3;
        /* Key Identifier Mode */
        uint8_t keyIdentifierMode : 2;
        /* Reserved */
        uint8_t reserved : 3;
        /* Frame Counter */
        uint32_t frameCounter;
        /* Key Identifier */
        uint8_t keyIdentifier;
    } MAC_RT_AUX_SECURITY_HEADER;
    
    // *****************************************************************************
    /* G3-PLC MAC RT header
       Summary
        This struct includes information related to MAC header
       Remarks:
        For more information, please refer to G3-PLC Specification
    */
    typedef struct __attribute__((packed, aligned(1))) {
        /* Frame Control Information */
        MAC_RT_FRAME_CONTROL frameControl;
        /* Sequence Number */
        uint8_t sequenceNumber;
        /* Destination PAN Identifier */
        uint16_t destinationPAN;
        /* Destination Address */
        MAC_RT_ADDRESS destinationAddress;
        /* Source PAN Identifier */
        uint16_t sourcePAN;
        /* Source Address */
        MAC_RT_ADDRESS sourceAddress;
        /* Security Header */
        MAC_RT_AUX_SECURITY_HEADER securityHeader;
    } MAC_RT_HEADER;
  2. Structure MAC_RT_TX_CFM_OBJ
    // *****************************************************************************
    /* G3-PLC MAC RT Transmission result
    
       Summary
        This struct includes a transmission result and timestamp.
    
       Remarks:
        None
    */
    typedef struct {
        /* MAC RT Status */
        MAC_RT_STATUS status;
        /* Flag to indicate Timestamp should be updated */
        bool updateTimestamp;
    } MAC_RT_TX_CFM_OBJ;
    The transmission result can have one of the following values:
    // *****************************************************************************
    /* G3-PLC MAC RT Status
    
       Summary
        The list of status values.
    
       Remarks:
        None
    */
    typedef enum {
        MAC_RT_STATUS_SUCCESS = 0x00,
        MAC_RT_STATUS_CHANNEL_ACCESS_FAILURE = 0xE1,
        MAC_RT_STATUS_DENIED = 0xE2,
        MAC_RT_STATUS_INVALID_INDEX = 0xF9,
        MAC_RT_STATUS_INVALID_PARAMETER = 0xE8,
        MAC_RT_STATUS_NO_ACK = 0xE9,
        MAC_RT_STATUS_READ_ONLY = 0xFB,
        MAC_RT_STATUS_TRANSACTION_OVERFLOW = 0xF1,
        MAC_RT_STATUS_UNSUPPORTED_ATTRIBUTE = 0xF4
    } MAC_RT_STATUS;