A library implementing IEEE 802.15.4 PHY functionality for the MCR20A transceiver. The PHY sublayer provides two services: the PHY data service and the PHY management service interfacing to the PHY sublayer management entity (PLME) service access point (SAP) (known as PLME-SAP). The PHY data service enables the transmission and reception of PHY protocol data units (PSDUs) over the media (radio).
Fork of fsl_phy_mcr20a by
The Freescale PHY Layer deals with the physical burst which is to be sent and/or received. It performs modulation and demodulation, transmitter and receiver switching, fragmentation, scrambling, interleaving, and error correction coding. The communication to the upper protocol layers is carried out through the Layer 1 Interface.
The PHY Layer is capable of executing the following sequences:
- I (Idle)
- R (Receive Sequence conditionally followed by a TxAck)
- T (Transmit Sequence)
- C (Standalone CCA)
- CCCA (Continuous CCA)
- TR (Transmit/Receive Sequence - transmit unconditionally followed by either an R or RxAck)
In addition to these sequences the PHY Layer also integrates a packet processor which determines whether the packet is MAC-compliant, and if it is, whether it is addressed to the end device. Another feature of the packet processor is Source Address Matching which can be viewed as an extension of packet filtering; however its function is very specific to its intended application (data-polling and indirect queue management by a PAN Coordinator).
Documentation
PHY/PhyPlmeData.c
- Committer:
- andreikovacs
- Date:
- 2015-08-18
- Revision:
- 0:764779eedf2d
File content as of revision 0:764779eedf2d:
/*! * Copyright (c) 2015, Freescale Semiconductor, Inc. * All rights reserved. * * \file PhyPlmeData.c * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * o Neither the name of Freescale Semiconductor, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /************************************************************************************ ************************************************************************************* * Include ************************************************************************************* ************************************************************************************/ #include "EmbeddedTypes.h" //#include "fsl_os_abstraction.h" #include "MCR20Drv.h" #include "MCR20Reg.h" #include "Phy.h" #include "PhyTypes.h" #include "PhyInterface.h" #include "MemManager.h" #include "FunctionLib.h" /************************************************************************************ ************************************************************************************* * Private macros ************************************************************************************* ************************************************************************************/ #define PHY_PARAMETERS_VALIDATION 1 /************************************************************************************ ************************************************************************************* * Private memory declarations ************************************************************************************* ************************************************************************************/ //2405 2410 2415 2420 2425 2430 2435 2440 2445 2450 2455 2460 2465 2470 2475 2480 static const uint8_t pll_int[16] = {0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D}; static const uint16_t pll_frac[16] = {0x2800, 0x5000, 0x7800, 0xA000, 0xC800, 0xF000, 0x1800, 0x4000, 0x6800, 0x9000, 0xB800, 0xE000, 0x0800, 0x3000, 0x5800, 0x8000}; extern Phy_PhyLocalStruct_t phyLocal[]; static uint8_t gPhyCurrentChannelPAN0 = 0x0B; static uint8_t gPhyCurrentChannelPAN1 = 0x0B; /************************************************************************************ ************************************************************************************* * Private prototypes ************************************************************************************* ************************************************************************************/ static void PhyRxRetry( uint32_t param ); /************************************************************************************ ************************************************************************************* * Public functions ************************************************************************************* ************************************************************************************/ /*! ********************************************************************************* * \brief This function will start a TX sequence. The packet will be sent OTA * * \param[in] pTxPacket pointer to the TX packet structure * \param[in] pRxParams pointer to RX parameters * \param[in] pTxParams pointer to TX parameters * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPdDataRequest( pdDataReq_t *pTxPacket, volatile phyRxParams_t *pRxParams, volatile phyTxParams_t *pTxParams ) { uint8_t phyRegs[5], phyCtrl4Reg; uint8_t *pTmpPsdu; //*tmp; #ifdef PHY_PARAMETERS_VALIDATION // null pointer if(NULL == pTxPacket) { return gPhyInvalidParameter_c; } // if CCA required ... if( (pTxPacket->CCABeforeTx == gPhyCCAMode3_c) || (pTxPacket->CCABeforeTx == gPhyEnergyDetectMode_c)) { // ... cannot perform other types than MODE1 and MODE2 return gPhyInvalidParameter_c; } #endif // PHY_PARAMETERS_VALIDATION if( gIdle_c != PhyPpGetState() ) { return gPhyBusy_c; } // load data into PB pTmpPsdu = MEM_BufferAlloc(gMaxPHYPacketSize_c + 1); *pTmpPsdu = pTxPacket->psduLength + 2; FLib_MemCpy(pTmpPsdu+1, &pTxPacket->pPsdu[0], pTxPacket->psduLength); MCR20Drv_PB_SPIBurstWrite(pTmpPsdu, (uint8_t) (pTxPacket->psduLength + 1)); /* including psduLength */ MEM_BufferFree(pTmpPsdu); #if 0 // load data into PB tmp = pTxPacket->pPsdu; pTmpPsdu = (uint8_t *) ((&pTxPacket->pPsdu[0])-1); *pTmpPsdu = pTxPacket->psduLength + 2; /* including 2 bytes of FCS */ MCR20Drv_PB_SPIBurstWrite( pTmpPsdu, (uint8_t) (pTxPacket->psduLength + 1)); /* including psduLength */ pTxPacket->pPsdu = tmp; #endif phyCtrl4Reg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4); phyRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[1], 4); // perform CCA before TX if required phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_CCABFRTX); phyCtrl4Reg &= (uint8_t) ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); if( pTxPacket->CCABeforeTx != gPhyNoCCABeforeTx_c ) { #if (gUseStandaloneCCABeforeTx_d == 0) phyRegs[PHY_CTRL1] |= (uint8_t) (cPHY_CTRL1_CCABFRTX); #endif phyCtrl4Reg |= (uint8_t) ((cPHY_CTRL4_CCATYPE & pTxPacket->CCABeforeTx) << (cPHY_CTRL4_CCATYPE_Shift_c)); } // slotted operation if( pTxPacket->slottedTx == gPhySlottedMode_c ) { phyRegs[PHY_CTRL1] |= (uint8_t) (cPHY_CTRL1_SLOTTED); } else { phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_SLOTTED); } // perform TxRxAck sequence if required by phyTxMode if(pTxPacket->ackRequired == gPhyRxAckRqd_c) { PhyIsrPassRxParams(pRxParams); phyRegs[PHY_CTRL1] |= (uint8_t) (cPHY_CTRL1_RXACKRQD); phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gTR_c; } else { PhyIsrPassRxParams(NULL); phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_RXACKRQD); phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gTX_c; } #if gUseStandaloneCCABeforeTx_d if( pTxPacket->CCABeforeTx != gPhyNoCCABeforeTx_c ) { // start the CCA or ED sequence (this depends on CcaType used) // immediately or by TC2', depending on a previous PhyTimeSetEventTrigger() call) if( pTxPacket->slottedTx == gPhySlottedMode_c ) pTxParams->numOfCca = 2; else pTxParams->numOfCca = 1; pTxParams->ackRequired = pTxPacket->ackRequired; phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gCCA_c; // at the end of the scheduled sequence, an interrupt will occur: // CCA , SEQ or TMR3 } else { pTxParams->numOfCca = 0; } #endif phyRegs[PHY_CTRL2] &= (uint8_t) ~(cPHY_CTRL2_SEQMSK); // unmask SEQ interrupt // ensure that no spurious interrupts are raised phyRegs[IRQSTS3] &= 0xF0; // do not change IRQ status phyRegs[IRQSTS3] |= (uint8_t) (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR3IRQ); // mask TMR3 interrupt MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 3); MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL2, phyRegs[PHY_CTRL2]); MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL4, phyCtrl4Reg); // start the TX or TRX sequence MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL1, phyRegs[PHY_CTRL1]); return gPhySuccess_c; } /*! ********************************************************************************* * \brief This function will start a RX sequence * * \param[in] phyRxMode slotted/unslotted * \param[in] pRxParams pointer to RX parameters * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPlmeRxRequest( phySlottedMode_t phyRxMode, phyRxParams_t * pRxParams ) { uint8_t phyRegs[5]; #ifdef PHY_PARAMETERS_VALIDATION if(NULL == pRxParams) { return gPhyInvalidParameter_c; } #endif // PHY_PARAMETERS_VALIDATION if( gIdle_c != PhyPpGetState() ) { return gPhyBusy_c; } pRxParams->phyRxMode = phyRxMode; if( NULL == pRxParams->pRxData ) { pRxParams->pRxData = MEM_BufferAlloc(sizeof(pdDataToMacMessage_t) + gMaxPHYPacketSize_c); } if( NULL == pRxParams->pRxData ) { phyTimeEvent_t event = { .timestamp = PhyTime_GetTimestamp() + gPhyRxRetryInterval_c, .parameter = (uint32_t)pRxParams, .callback = PhyRxRetry, }; PhyTime_ScheduleEvent( &event ); return gPhyTRxOff_c; } PhyIsrPassRxParams(pRxParams); pRxParams->pRxData->msgData.dataInd.pPsdu = (uint8_t*)&pRxParams->pRxData->msgData.dataInd.pPsdu + sizeof(pRxParams->pRxData->msgData.dataInd.pPsdu); phyRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[1], 4); // slotted operation if(gPhySlottedMode_c == phyRxMode) { phyRegs[PHY_CTRL1] |= (uint8_t) (cPHY_CTRL1_SLOTTED); } else { phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_SLOTTED); } // program the RX sequence phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gRX_c; phyRegs[PHY_CTRL2] &= (uint8_t) ~(cPHY_CTRL2_SEQMSK); // unmask SEQ interrupt // ensure that no spurious interrupts are raised phyRegs[IRQSTS3] &= 0xF0; // do not change IRQ status phyRegs[IRQSTS3] |= (uint8_t) (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR3IRQ); // mask TMR3 interrupt MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 3); MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL2, phyRegs[PHY_CTRL2]); // start the RX sequence MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL1, phyRegs[PHY_CTRL1]); return gPhySuccess_c; } /*! ********************************************************************************* * \brief This function will start a CCA / CCCA sequence * * \param[in] ccaParam the type of CCA * \param[in] cccaMode continuous or single CCA * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPlmeCcaEdRequest( phyCCAType_t ccaParam, phyContCCAMode_t cccaMode ) { uint8_t phyRegs[5]; #ifdef PHY_PARAMETERS_VALIDATION // illegal CCA type if( (ccaParam != gPhyCCAMode1_c) && (ccaParam != gPhyCCAMode2_c) && (ccaParam != gPhyCCAMode3_c) && (ccaParam != gPhyEnergyDetectMode_c)) { return gPhyInvalidParameter_c; } // cannot perform Continuous CCA using ED type if( (ccaParam == gPhyEnergyDetectMode_c) && (cccaMode == gPhyContCcaEnabled) ) { return gPhyInvalidParameter_c; } #endif // PHY_PARAMETERS_VALIDATION if( gIdle_c != PhyPpGetState() ) { return gPhyBusy_c; } // write in PHY CTRL4 the desired type of CCA phyRegs[0] = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4); phyRegs[0] &= (uint8_t) ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); phyRegs[0] |= (uint8_t) ((cPHY_CTRL4_CCATYPE & ccaParam) << (cPHY_CTRL4_CCATYPE_Shift_c)); MCR20Drv_DirectAccessSPIWrite( (uint8_t)PHY_CTRL4, phyRegs[0]); phyRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[1], 4); // continuous CCA if(cccaMode == gPhyContCcaEnabled) { // start the continuous CCA sequence // immediately or by TC2', depending on a previous PhyTimeSetEventTrigger() call) phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gCCCA_c; // at the end of the scheduled sequence, an interrupt will occur: // CCA , SEQ or TMR3 } // normal CCA (not continuous) else { // start the CCA or ED sequence (this depends on CcaType used) // immediately or by TC2', depending on a previous PhyTimeSetEventTrigger() call) phyRegs[PHY_CTRL1] &= (uint8_t) ~(cPHY_CTRL1_XCVSEQ); phyRegs[PHY_CTRL1] |= gCCA_c; // at the end of the scheduled sequence, an interrupt will occur: // CCA , SEQ or TMR3 } phyRegs[PHY_CTRL2] &= (uint8_t) ~(cPHY_CTRL2_SEQMSK); // unmask SEQ interrupt // ensure that no spurious interrupts are raised phyRegs[IRQSTS3] &= 0xF0; // do not change IRQ status phyRegs[IRQSTS3] |= (uint8_t) (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR3IRQ); // mask TMR3 interrupt MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 3); // start the CCA/ED or CCCA sequence MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL2, phyRegs[PHY_CTRL2]); MCR20Drv_DirectAccessSPIWrite( (uint8_t) PHY_CTRL1, phyRegs[PHY_CTRL1]); return gPhySuccess_c; } /*! ********************************************************************************* * \brief This function will set the channel number for the specified PAN * * \param[in] channel new channel number * \param[in] pan the PAN registers (0/1) * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPlmeSetCurrentChannelRequest ( uint8_t channel, uint8_t pan ) { #ifdef PHY_PARAMETERS_VALIDATION if((channel < 11) || (channel > 26)) { return gPhyInvalidParameter_c; } #endif // PHY_PARAMETERS_VALIDATION if( !pan ) { gPhyCurrentChannelPAN0 = channel; MCR20Drv_DirectAccessSPIWrite(PLL_INT0, pll_int[channel - 11]); MCR20Drv_DirectAccessSPIMultiByteWrite(PLL_FRAC0_LSB, (uint8_t *) &pll_frac[channel - 11], 2); } else { gPhyCurrentChannelPAN1 = channel; MCR20Drv_IndirectAccessSPIWrite(PLL_INT1, pll_int[channel - 11]); MCR20Drv_IndirectAccessSPIMultiByteWrite(PLL_FRAC1_LSB, (uint8_t *) &pll_frac[channel - 11], 2); } return gPhySuccess_c; } /*! ********************************************************************************* * \brief This function will return the current channel for a specified PAN * * \param[in] pan the PAN registers (0/1) * * \return uint8_t current channel number * ********************************************************************************** */ uint8_t PhyPlmeGetCurrentChannelRequest ( uint8_t pan ) { if( !pan ) return gPhyCurrentChannelPAN0; else return gPhyCurrentChannelPAN1; } /*! ********************************************************************************* * \brief This function will set the radio Tx power * * \param[in] pwrStep the Tx power * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPlmeSetPwrLevelRequest ( uint8_t pwrStep ) { #ifdef PHY_PARAMETERS_VALIDATION if((pwrStep < 3) || (pwrStep > 31)) //-40 dBm to 16 dBm { return gPhyInvalidParameter_c; } #endif // PHY_PARAMETERS_VALIDATION MCR20Drv_DirectAccessSPIWrite(PA_PWR, (uint8_t)(pwrStep & 0x1F)); return gPhySuccess_c; } /*--------------------------------------------------------------------------- * Name: PhyPlmeSetLQIModeRequest * Description: - * Parameters: - * Return: - *---------------------------------------------------------------------------*/ uint8_t PhyPlmeSetLQIModeRequest(uint8_t lqiMode) { uint8_t currentMode; currentMode = MCR20Drv_IndirectAccessSPIRead(CCA_CTRL); lqiMode ? (currentMode |= cCCA_CTRL_LQI_RSSI_NOT_CORR) : (currentMode &= (~((uint8_t)cCCA_CTRL_LQI_RSSI_NOT_CORR))); MCR20Drv_IndirectAccessSPIWrite(CCA_CTRL, currentMode); return gPhySuccess_c; } /*--------------------------------------------------------------------------- * Name: PhyPlmeGetRSSILevelRequest * Description: - * Parameters: - * Return: - *---------------------------------------------------------------------------*/ uint8_t PhyPlmeGetRSSILevelRequest(void) { return MCR20Drv_IndirectAccessSPIRead(RSSI); } /*! ********************************************************************************* * \brief This function will set the value of PHY PIBs * * \param[in] pibId the Id of the PIB * \param[in] pibValue the new value of the PIB * \param[in] phyRegistrySet the PAN registers (0/1) * \param[in] instanceId the instance of the PHY * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPlmeSetPIBRequest(phyPibId_t pibId, uint64_t pibValue, uint8_t phyRegistrySet, instanceId_t instanceId) { phyStatus_t result = gPhySuccess_c; switch(pibId) { case gPhyPibCurrentChannel_c: { result = PhyPlmeSetCurrentChannelRequest((uint8_t) pibValue, phyRegistrySet); } break; case gPhyPibTransmitPower_c: { result = PhyPlmeSetPwrLevelRequest((uint8_t) pibValue); } break; case gPhyPibLongAddress_c: { uint64_t longAddr = pibValue; result = PhyPpSetLongAddr((uint8_t *) &longAddr, phyRegistrySet); } break; case gPhyPibShortAddress_c: { uint16_t shortAddr = (uint16_t) pibValue; result = PhyPpSetShortAddr((uint8_t *) &shortAddr, phyRegistrySet); } break; case gPhyPibPanId_c: { uint16_t panId = (uint16_t) pibValue; result = PhyPpSetPanId((uint8_t *) &panId, phyRegistrySet); } break; case gPhyPibPanCoordinator_c: { bool_t macRole = (bool_t) pibValue; result = PhyPpSetMacRole(macRole, phyRegistrySet); } break; case gPhyPibCurrentPage_c: { /* Nothinh to do... */ } break; case gPhyPibPromiscuousMode_c: { PhyPpSetPromiscuous((uint8_t)pibValue); } break; case gPhyPibRxOnWhenIdle: { PhyPlmeSetRxOnWhenIdle( (bool_t)pibValue, instanceId ); } break; case gPhyPibFrameWaitTime_c: { PhyPlmeSetFrameWaitTime( (uint32_t)pibValue, instanceId ); } break; case gPhyPibDeferTxIfRxBusy_c: { if( pibValue ) phyLocal[instanceId].flags |= gPhyFlagDeferTx_c; else phyLocal[instanceId].flags &= ~gPhyFlagDeferTx_c; } break; default: { result = gPhyUnsupportedAttribute_c; } break; } return result; } /*! ********************************************************************************* * \brief This function will return the value of PHY PIBs * * \param[in] pibId the Id of the PIB * \param[out] pibValue pointer to a location where the value will be stored * \param[in] phyRegistrySet the PAN registers (0/1) * \param[in] instanceId the instance of the PHY * * \return phyStatus_t * ********************************************************************************** */ phyStatus_t PhyPlmeGetPIBRequest(phyPibId_t pibId, uint64_t * pibValue, uint8_t phyRegistrySet, instanceId_t instanceId) { phyStatus_t result = gPhySuccess_c; switch(pibId) { case gPhyPibCurrentChannel_c: { *((uint8_t*)pibValue) = (uint64_t) PhyPlmeGetCurrentChannelRequest(phyRegistrySet); } break; case gPhyPibTransmitPower_c: { *((uint8_t*)pibValue) = MCR20Drv_DirectAccessSPIRead(PA_PWR); } break; case gPhyPibLongAddress_c: { if( !phyRegistrySet ) MCR20Drv_IndirectAccessSPIMultiByteRead( MACLONGADDRS0_0, (uint8_t*)pibValue, 8); else MCR20Drv_IndirectAccessSPIMultiByteRead( MACLONGADDRS1_0, (uint8_t*)pibValue, 8); } break; case gPhyPibShortAddress_c: { if( !phyRegistrySet ) MCR20Drv_IndirectAccessSPIMultiByteRead( MACSHORTADDRS0_LSB, (uint8_t*)pibValue, 2); else MCR20Drv_IndirectAccessSPIMultiByteRead( MACSHORTADDRS1_LSB, (uint8_t*)pibValue, 2); } break; case gPhyPibPanId_c: { if( !phyRegistrySet ) MCR20Drv_IndirectAccessSPIMultiByteRead( MACPANID0_LSB, (uint8_t*)pibValue, 2); else MCR20Drv_IndirectAccessSPIMultiByteRead( MACPANID1_LSB, (uint8_t*)pibValue, 2); } break; case gPhyPibPanCoordinator_c: { uint8_t phyReg; if( !phyRegistrySet ) { phyReg = MCR20Drv_DirectAccessSPIRead( PHY_CTRL4); phyReg = (phyReg & cPHY_CTRL4_PANCORDNTR0) == cPHY_CTRL4_PANCORDNTR0; } else { phyReg = MCR20Drv_IndirectAccessSPIRead( (uint8_t) DUAL_PAN_CTRL); phyReg = (phyReg & cDUAL_PAN_CTRL_PANCORDNTR1) == cDUAL_PAN_CTRL_PANCORDNTR1; } *((uint8_t*)pibValue) = phyReg; } break; case gPhyPibRxOnWhenIdle: { *((uint8_t*)pibValue) = !!(phyLocal[instanceId].flags & gPhyFlagRxOnWhenIdle_c); } break; case gPhyPibFrameWaitTime_c: { *((uint8_t*)pibValue) = phyLocal[instanceId].maxFrameWaitTime; } break; case gPhyPibDeferTxIfRxBusy_c: { *((uint8_t*)pibValue) = !!(phyLocal[instanceId].flags & gPhyFlagDeferTx_c); } break; default: { result = gPhyUnsupportedAttribute_c; } break; } return result; } /************************************************************************************ ************************************************************************************* * Private functions ************************************************************************************* ************************************************************************************/ static void PhyRxRetry( uint32_t param ) { PhyPlmeRxRequest( ((phyRxParams_t*)param)->phyRxMode, (phyRxParams_t*)param ); }