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
Diff: PHY/PhyStateMachine.c
- Revision:
- 0:764779eedf2d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PHY/PhyStateMachine.c Tue Aug 18 12:41:42 2015 +0000 @@ -0,0 +1,1044 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file PhyStateMachine.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. +*/ + + +#ifdef gSrcTask_d +#undef gSrcTask_d +#endif + +#define gSrcTask_d PHY + + +/************************************************************************************ +************************************************************************************* +* Include +************************************************************************************* +************************************************************************************/ +#include "EmbeddedTypes.h" + +//#include "fsl_os_abstraction.h" + +#include "PhyInterface.h" +#include "Phy.h" + + +#include "MemManager.h" +#include "FunctionLib.h" +#if 0 +#include "Messaging.h" +#include "Panic.h" +#endif + +#include "MCR20Drv.h" +#include "MCR20Reg.h" + +#include "AspInterface.h" +#include "MpmInterface.h" + +/************************************************************************************ +************************************************************************************* +* Public macros +************************************************************************************* +************************************************************************************/ +#define mPhyMaxIdleRxDuration_c (0xF00000) /* [sym] */ + +#define ProtectFromXcvrInterrupt() ProtectFromMCR20Interrupt() +#define UnprotectFromXcvrInterrupt() UnprotectFromMCR20Interrupt() + +/************************************************************************************ +************************************************************************************* +* Private type definitions +************************************************************************************* +************************************************************************************/ + +/************************************************************************************ +************************************************************************************* +* Private prototypes +************************************************************************************* +************************************************************************************/ +static void Phy24Task(Phy_PhyLocalStruct_t *pPhyData); + +static phyStatus_t Phy_HandlePdDataReq( Phy_PhyLocalStruct_t *pPhyData, macToPdDataMessage_t * pMsg ); + +static void Phy_EnterIdle( Phy_PhyLocalStruct_t *pPhyData ); + +static void PLME_SendMessage(Phy_PhyLocalStruct_t *pPhyData, phyMessageId_t msgType); + +static void PD_SendMessage(Phy_PhyLocalStruct_t *pPhyData, phyMessageId_t msgType); + + +static void MSG_InitQueue(macPhyInputQueue_t * pMacPhyQueue); +static void MSG_Queue(macPhyInputQueue_t * pMacPhyQueue, void * pMsgIn); +static void MSG_QueueHead(macPhyInputQueue_t * pMacPhyQueue, void * pMsgIn); +static bool_t MSG_Pending(macPhyInputQueue_t * pMacPhyQueue); +static void * MSG_DeQueue(macPhyInputQueue_t * pMacPhyQueue); + +/************************************************************************************ +************************************************************************************* +* Private memory declarations +************************************************************************************* +************************************************************************************/ +Phy_PhyLocalStruct_t phyLocal[gPhyInstancesCnt_c]; +extern volatile uint32_t mPhySeqTimeout; + +/************************************************************************************ +************************************************************************************* +* Public functions +************************************************************************************* +************************************************************************************/ + +/*! ********************************************************************************* +* \brief This function creates the PHY task +* +********************************************************************************** */ +void Phy_Init(void) +{ + uint32_t i; + + PhyHwInit(); + ASP_Init( 0, gAspInterfaceId ); + MPM_Init(); + + for( i=0; i<gPhyInstancesCnt_c; i++ ) + { + phyLocal[i].flags = gPhyFlagDeferTx_c; + phyLocal[i].rxParams.pRxData = NULL; + + /* Prepare input queues.*/ + MSG_InitQueue( &phyLocal[i].macPhyInputQueue ); + } + + PhyIsrPassRxParams( NULL ); + PhyPlmeSetPwrState( gPhyDefaultIdlePwrMode_c ); +} + +/*! ********************************************************************************* +* \brief This function binds a MAC instance to a PHY instance +* +* \param[in] instanceId The instance of the MAC +* +* \return The instance of the PHY. +* +********************************************************************************** */ +instanceId_t BindToPHY( instanceId_t macInstance ) +{ + return 0; +} + +/*! ********************************************************************************* +* \brief This function registers the MAC PD and PLME SAP handlers +* +* \param[in] pPD_MAC_SapHandler Pointer to the MAC PD handler function +* \param[in] pPLME_MAC_SapHandler Pointer to the MAC PLME handler function +* \param[in] instanceId The instance of the PHY +* +* \return The status of the operation. +* +********************************************************************************** */ +void Phy_RegisterSapHandlers( PD_MAC_SapHandler_t pPD_MAC_SapHandler, + PLME_MAC_SapHandler_t pPLME_MAC_SapHandler, + instanceId_t instanceId ) +{ + phyLocal[instanceId].PD_MAC_SapHandler = pPD_MAC_SapHandler; + phyLocal[instanceId].PLME_MAC_SapHandler = pPLME_MAC_SapHandler; +} + +/*! ********************************************************************************* +* \brief This function represents the PHY's task +* +* \param[in] taskParam The instance of the PHY +* +********************************************************************************** */ +static void Phy24Task(Phy_PhyLocalStruct_t *pPhyStruct) +{ + uint8_t state; + phyMessageHeader_t * pMsgIn; + phyStatus_t status = gPhySuccess_c; + + ProtectFromXcvrInterrupt(); + state = PhyGetSeqState(); + + /* Handling messages from upper layer */ + while( MSG_Pending(&pPhyStruct->macPhyInputQueue) ) + { + /* PHY doesn't free dynamic alocated messages! */ + pMsgIn = MSG_DeQueue( &pPhyStruct->macPhyInputQueue ); + pPhyStruct->currentMacInstance = pMsgIn->macInstance; + + if( gRX_c == state ) + { + if( (pPhyStruct->flags & gPhyFlagDeferTx_c) && (pMsgIn->msgType == gPdDataReq_c) ) + { + macToPdDataMessage_t *pPD = (macToPdDataMessage_t*)pMsgIn; + uint8_t phyReg = MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F; + /* Check for an Rx in progress, and if the packet can be defered. + Packet cannot be defered */ + if( (pPD->msgData.dataReq.CCABeforeTx != gPhyNoCCABeforeTx_c) && + (pPD->msgData.dataReq.startTime == gPhySeqStartAsap_c) && + (pPD->msgData.dataReq.slottedTx == gPhyUnslottedMode_c) && + (phyReg <= 0x06 || phyReg == 0x15 || phyReg == 0x16) ) + { + MSG_QueueHead( &pPhyStruct->macPhyInputQueue, pMsgIn ); + UnprotectFromXcvrInterrupt(); + return; + } + } + +// if( pPhyStruct->flags & gPhyFlagIdleRx_c ) + { + PhyPlmeForceTrxOffRequest(); + state = gIdle_c; + pPhyStruct->flags &= ~(gPhyFlagIdleRx_c); + } + } + + if( gIdle_c != state ) + { + /* try again later */ + MSG_QueueHead( &pPhyStruct->macPhyInputQueue, pMsgIn ); + UnprotectFromXcvrInterrupt(); + return; + } + +#if gMpmIncluded_d + if( status == gPhySuccess_c ) + { + status = MPM_PrepareForTx( pMsgIn->macInstance ); + } +#endif + + if( status == gPhySuccess_c ) + { + pPhyStruct->flags &= ~(gPhyFlagIdleRx_c); + + switch( pMsgIn->msgType ) + { + case gPdDataReq_c: + status = Phy_HandlePdDataReq( pPhyStruct, (macToPdDataMessage_t *)pMsgIn ); + break; + case gPlmeCcaReq_c: + status = PhyPlmeCcaEdRequest(gPhyCCAMode1_c, gPhyContCcaDisabled); + break; + case gPlmeEdReq_c: + status = PhyPlmeCcaEdRequest(gPhyEnergyDetectMode_c, gPhyContCcaDisabled); + break; + default: + status = gPhyInvalidPrimitive_c; + } + } + + /* Check status */ + if( gPhySuccess_c == status ) + { + UnprotectFromXcvrInterrupt(); + return; + } + else + { + switch( pMsgIn->msgType ) + { + case gPdDataReq_c: + if( ((macToPdDataMessage_t*)pMsgIn)->msgData.dataReq.CCABeforeTx == gPhyNoCCABeforeTx_c ) + { + PD_SendMessage(pPhyStruct, gPdDataCnf_c); + break; + } + /* Fallthorough */ + case gPlmeCcaReq_c: + pPhyStruct->channelParams.channelStatus = gPhyChannelBusy_c; + PLME_SendMessage(pPhyStruct, gPlmeCcaCnf_c); + break; + case gPlmeEdReq_c: + pPhyStruct->channelParams.energyLeveldB = 0; + PLME_SendMessage(pPhyStruct, gPlmeEdCnf_c); + break; + default: + PLME_SendMessage(pPhyStruct, gPlmeTimeoutInd_c); + } + } + }/* while( MSG_Pending(&pPhyStruct->macPhyInputQueue) ) */ + + UnprotectFromXcvrInterrupt(); + + /* Check if PHY can enter Idle state */ + if( gIdle_c == state ) + { + Phy_EnterIdle( pPhyStruct ); + } +} + +/*! ********************************************************************************* +* \brief This is the PD SAP message handler +* +* \param[in] pMsg Pointer to the PD request message +* \param[in] instanceId The instance of the PHY +* +* \return The status of the operation. +* +********************************************************************************** */ +phyStatus_t MAC_PD_SapHandler(macToPdDataMessage_t *pMsg, instanceId_t phyInstance) +{ + phyStatus_t result = gPhySuccess_c; + uint8_t baseIndex = 0; + + if( NULL == pMsg ) + { + return gPhyInvalidParameter_c; + } + +#if gMpmIncluded_d + if( pMsg->msgType == gPdIndQueueInsertReq_c || pMsg->msgType == gPdIndQueueRemoveReq_c ) + { + baseIndex = MPM_GetRegSet( MPM_GetPanIndex( pMsg->macInstance ) ) * + (gPhyIndirectQueueSize_c/gMpmPhyPanRegSets_c); + } +#endif + + switch( pMsg->msgType ) + { + case gPdIndQueueInsertReq_c: + result = PhyPp_IndirectQueueInsert(baseIndex + pMsg->msgData.indQueueInsertReq.index, + pMsg->msgData.indQueueInsertReq.checksum, + phyInstance); + break; + + case gPdIndQueueRemoveReq_c: + result = PhyPp_RemoveFromIndirect(baseIndex + pMsg->msgData.indQueueRemoveReq.index, + phyInstance); + break; + + case gPdDataReq_c: + MSG_Queue(&phyLocal[phyInstance].macPhyInputQueue, pMsg); + Phy24Task( &phyLocal[phyInstance] ); + break; + + default: + result = gPhyInvalidPrimitive_c; + } + + return result; +} + +/*! ********************************************************************************* +* \brief This is the PLME SAP message handler +* +* \param[in] pMsg Pointer to the PLME request message +* \param[in] instanceId The instance of the PHY +* +* \return phyStatus_t The status of the operation. +* +********************************************************************************** */ +phyStatus_t MAC_PLME_SapHandler(macToPlmeMessage_t * pMsg, instanceId_t phyInstance) +{ + Phy_PhyLocalStruct_t *pPhyStruct = &phyLocal[phyInstance]; + uint8_t phyRegSet = 0; +#if gMpmIncluded_d + phyStatus_t result; + int32_t panIdx = MPM_GetPanIndex( pMsg->macInstance ); + + phyRegSet = MPM_GetRegSet( panIdx ); +#endif + + if( NULL == pMsg ) + { + return gPhyInvalidParameter_c; + } + + switch( pMsg->msgType ) + { + case gPlmeEdReq_c: + case gPlmeCcaReq_c: + MSG_Queue(&phyLocal[phyInstance].macPhyInputQueue, pMsg); + Phy24Task( &phyLocal[phyInstance] ); + break; + + case gPlmeSetReq_c: +#if gMpmIncluded_d + result = MPM_SetPIB(pMsg->msgData.setReq.PibAttribute, + &pMsg->msgData.setReq.PibAttributeValue, + panIdx ); + if( !MPM_isPanActive(panIdx) ) + { + return result; + } +#endif + return PhyPlmeSetPIBRequest(pMsg->msgData.setReq.PibAttribute, pMsg->msgData.setReq.PibAttributeValue, phyRegSet, phyInstance); + + case gPlmeGetReq_c: +#if gMpmIncluded_d + if( gPhySuccess_c == MPM_GetPIB(pMsg->msgData.getReq.PibAttribute, pMsg->msgData.getReq.pPibAttributeValue, panIdx) ) + { + break; + } +#endif + return PhyPlmeGetPIBRequest( pMsg->msgData.getReq.PibAttribute, pMsg->msgData.getReq.pPibAttributeValue, phyRegSet, phyInstance); + + case gPlmeSetTRxStateReq_c: + if(gPhySetRxOn_c == pMsg->msgData.setTRxStateReq.state) + { + if( PhyIsIdleRx(phyInstance) ) + { + PhyPlmeForceTrxOffRequest(); + } + else if( gIdle_c != PhyGetSeqState() ) + { + return gPhyBusy_c; + } +#if gMpmIncluded_d + /* If another PAN has the RxOnWhenIdle PIB set, enable the DualPan Auto mode */ + if( gPhySuccess_c != MPM_PrepareForRx( pMsg->macInstance ) ) + return gPhyBusy_c; +#endif + pPhyStruct->flags &= ~(gPhyFlagIdleRx_c); + Phy_SetSequenceTiming(pMsg->msgData.setTRxStateReq.startTime, + pMsg->msgData.setTRxStateReq.rxDuration); + + return PhyPlmeRxRequest(pMsg->msgData.setTRxStateReq.slottedMode, (phyRxParams_t *) &pPhyStruct->rxParams); + } + else if (gPhyForceTRxOff_c == pMsg->msgData.setTRxStateReq.state) + { +#if gMpmIncluded_d + if( !MPM_isPanActive(panIdx) ) + return gPhySuccess_c; +#endif + pPhyStruct->flags &= ~(gPhyFlagIdleRx_c); + PhyPlmeForceTrxOffRequest(); + } + break; + + default: + return gPhyInvalidPrimitive_c; + } + + return gPhySuccess_c; +} + +/*! ********************************************************************************* +* \brief This function programs a new TX sequence +* +* \param[in] pMsg Pointer to the PD request message +* \param[in] pPhyData pointer to PHY data +* +* \return The status of the operation. +* +********************************************************************************** */ +static phyStatus_t Phy_HandlePdDataReq( Phy_PhyLocalStruct_t *pPhyData, macToPdDataMessage_t * pMsg ) +{ + phyStatus_t status = gPhySuccess_c; + uint32_t time; + + if( NULL == pMsg->msgData.dataReq.pPsdu ) + { + return gPhyInvalidParameter_c; + } + + ProtectFromXcvrInterrupt(); + + if( pMsg->msgData.dataReq.startTime != gPhySeqStartAsap_c ) + { + PhyTimeSetEventTrigger( (uint16_t) pMsg->msgData.dataReq.startTime ); + } + + status = PhyPdDataRequest(&pMsg->msgData.dataReq , &pPhyData->rxParams, &pPhyData->txParams); + + if( pMsg->msgData.dataReq.txDuration != gPhySeqStartAsap_c ) + { + OSA_EnterCritical(kCriticalDisableInt); + PhyTimeReadClock( &time ); + time += pMsg->msgData.dataReq.txDuration; + /* Compensate PHY overhead, including WU time */ + time += 54; + PhyTimeSetEventTimeout( &time ); + OSA_ExitCritical(kCriticalDisableInt); + } + + UnprotectFromXcvrInterrupt(); + + if( gPhySuccess_c != status ) + { + PhyTimeDisableEventTrigger(); + PhyTimeDisableEventTimeout(); + } + + return status; +} + +/*! ********************************************************************************* +* \brief This function sets the start time and the timeout value for a sequence. +* +* \param[in] startTime The absolute start time for the sequence. +* If startTime is gPhySeqStartAsap_c, the start timer is disabled. +* \param[in] seqDuration The duration of the sequence. +* If seqDuration is 0xFFFFFFFF, the timeout is disabled. +* +********************************************************************************** */ +void Phy_SetSequenceTiming(uint32_t startTime, uint32_t seqDuration) +{ + uint32_t endTime; + + OSA_EnterCritical(kCriticalDisableInt); + + if( gPhySeqStartAsap_c == startTime ) + { + PhyTimeReadClock( &endTime ); + } + else + { + PhyTimeSetEventTrigger( (uint16_t) startTime ); + endTime = startTime & gPhyTimeMask_c; + } + + if( 0xFFFFFFFF != seqDuration ) + { + endTime += seqDuration; + endTime = endTime & gPhyTimeMask_c; + + PhyTimeSetEventTimeout( &(endTime) ); + } + + OSA_ExitCritical(kCriticalDisableInt); +} + +/*! ********************************************************************************* +* \brief This function starts the IdleRX if the PhyRxOnWhenIdle PIB is set +* +* \param[in] pPhyData pointer to PHY data +* +********************************************************************************** */ +void Phy_EnterIdle( Phy_PhyLocalStruct_t *pPhyData ) +{ + if( (pPhyData->flags & gPhyFlagRxOnWhenIdle_c) +#if gMpmIncluded_d + /* Prepare the Active PAN/PANs */ + && (gPhySuccess_c == MPM_PrepareForRx(gInvalidInstanceId_c)) +#endif + ) + { + pPhyData->flags |= gPhyFlagIdleRx_c; + Phy_SetSequenceTiming( gPhySeqStartAsap_c, mPhyMaxIdleRxDuration_c ); + (void)PhyPlmeRxRequest( gPhyUnslottedMode_c, (phyRxParams_t*)&pPhyData->rxParams ); + } + else + { + pPhyData->flags &= ~(gPhyFlagIdleRx_c); + } +} + +/*! ********************************************************************************* +* \brief This function sets the value of the maxFrameWaitTime PIB +* +* \param[in] instanceId The instance of the PHY +* \param[in] time The maxFrameWaitTime value +* +********************************************************************************** */ +void PhyPlmeSetFrameWaitTime( uint32_t time, instanceId_t instanceId ) +{ + phyLocal[instanceId].maxFrameWaitTime = time; +} + +/*! ********************************************************************************* +* \brief This function sets the state of the PhyRxOnWhenIdle PIB +* +* \param[in] instanceId The instance of the PHY +* \param[in] state The PhyRxOnWhenIdle value +* +********************************************************************************** */ +void PhyPlmeSetRxOnWhenIdle( bool_t state, instanceId_t instanceId ) +{ + uint8_t radioState = PhyGetSeqState(); +#if gMpmIncluded_d + /* Check if at least one PAN has RxOnWhenIdle set */ + if( FALSE == state ) + { + uint32_t i; + + for( i=0; i<gMpmMaxPANs_c; i++ ) + { + MPM_GetPIB( gPhyPibRxOnWhenIdle, &state, i ); + if( state ) + break; + } + } +#endif + if( state ) + { + phyLocal[instanceId].flags |= gPhyFlagRxOnWhenIdle_c; + if( radioState == gIdle_c) + { + Phy_EnterIdle( &phyLocal[instanceId] ); + } +#if gMpmIncluded_d + else if( (radioState == gRX_c) && (phyLocal[instanceId].flags & gPhyFlagIdleRx_c) ) + { + PhyPlmeForceTrxOffRequest(); + Phy_EnterIdle( &phyLocal[instanceId] ); + } +#endif + } + else + { + phyLocal[instanceId].flags &= ~gPhyFlagRxOnWhenIdle_c; + if( (radioState == gRX_c) && (phyLocal[instanceId].flags & gPhyFlagIdleRx_c) ) + { + PhyPlmeForceTrxOffRequest(); + phyLocal[instanceId].flags &= ~gPhyFlagIdleRx_c; + } + } +} + +/*! ********************************************************************************* +* \brief This function starts the IdleRX if the PhyRxOnWhenIdle PIB is set +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +bool_t PhyIsIdleRx( instanceId_t instanceId ) +{ + if( (phyLocal[instanceId].flags & gPhyFlagIdleRx_c) && (gRX_c == PhyGetSeqState())) + return TRUE; + + return FALSE; +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that a TX operation completed successfully. +* If the received ACK has FP=1, then the radio will enter RX state for +* maxFrameWaitTime duration. +* +* \param[in] instanceId The instance of the PHY +* \param[in] framePending The value of the framePending bit for the received ACK +* +********************************************************************************** */ +void Radio_Phy_PdDataConfirm(instanceId_t instanceId, bool_t framePending) +{ + PhyTimeDisableEventTimeout(); + + if( framePending ) + { + phyLocal[instanceId].flags |= gPhyFlagFramePending_c; + if( phyLocal[instanceId].maxFrameWaitTime > 0 ) + { + /* Restart Rx asap if an ACK with FP=1 is received */ + phyLocal[instanceId].flags &= ~(gPhyFlagIdleRx_c); + Phy_SetSequenceTiming( gPhySeqStartAsap_c, phyLocal[instanceId].maxFrameWaitTime ); + PhyPlmeRxRequest( gPhyUnslottedMode_c, (phyRxParams_t *) &phyLocal[instanceId].rxParams ); + } + } + else + { + phyLocal[instanceId].flags &= ~gPhyFlagFramePending_c; + } + + PD_SendMessage(&phyLocal[instanceId], gPdDataCnf_c); + Phy24Task(&phyLocal[instanceId]); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that new data has been received +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +void Radio_Phy_PdDataIndication(instanceId_t instanceId) +{ + PhyTimeDisableEventTimeout(); + + PD_SendMessage(&phyLocal[instanceId], gPdDataInd_c); + Phy24Task(&phyLocal[instanceId]); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that timer1 compare match occured +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +void Radio_Phy_TimeWaitTimeoutIndication(instanceId_t instanceId) +{ + PhyTime_ISR(); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that a CCA sequence has finished +* +* \param[in] instanceId The instance of the PHY +* \param[in] phyChannelStatus The status of the channel: Idle/Busy +* +* \return None. +* +********************************************************************************** */ +void Radio_Phy_PlmeCcaConfirm(phyStatus_t phyChannelStatus, instanceId_t instanceId) +{ + PhyTimeDisableEventTimeout(); + + phyLocal[instanceId].channelParams.channelStatus = phyChannelStatus; + + PLME_SendMessage(&phyLocal[instanceId], gPlmeCcaCnf_c); + Phy24Task(&phyLocal[instanceId]); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that a ED sequence has finished +* +* \param[in] instanceId The instance of the PHY +* \param[in] energyLevel The enetgy level on the channel. +* \param[in] energyLeveldB The energy level in DB +* +********************************************************************************** */ +void Radio_Phy_PlmeEdConfirm(uint8_t energyLeveldB, instanceId_t instanceId) +{ + PhyTimeDisableEventTimeout(); + + phyLocal[instanceId].channelParams.energyLeveldB = energyLeveldB; + + PLME_SendMessage(&phyLocal[instanceId], gPlmeEdCnf_c); + Phy24Task(&phyLocal[instanceId]); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that the programmed sequence has timed out +* The Radio is forced to Idle. +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +void Radio_Phy_TimeRxTimeoutIndication(instanceId_t instanceId) +{ + if( !(phyLocal[instanceId].flags & gPhyFlagIdleRx_c) ) + PLME_SendMessage(&phyLocal[instanceId], gPlmeTimeoutInd_c); + + Phy24Task(&phyLocal[instanceId]); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that the programmed sequence has started +* +* \param[in] instanceId The instance of the PHY +* +* \return None. +* +********************************************************************************** */ +void Radio_Phy_TimeStartEventIndication(instanceId_t instanceId) +{ +#ifdef MAC_PHY_DEBUG + PLME_SendMessage(&phyLocal[instanceId], gPlme_StartEventInd_c); + Phy24Task(&phyLocal[instanceId]); +#endif +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that a SFD was detected. +* Also, if there is not enough time to receive the entire packet, the +* RX timeout will be extended. +* +* \param[in] instanceId The instance of the PHY +* \param[in] frameLen the length of the PSDU +* +********************************************************************************** */ +void Radio_Phy_PlmeRxSfdDetect(instanceId_t instanceId, uint32_t frameLen) +{ + if( phyLocal[instanceId].flags & gPhyFlagDeferTx_c ) + { + uint32_t currentTime; + uint32_t time; + + OSA_EnterCritical(kCriticalDisableInt); + + //Read currentTime and Timeout values [sym] + PhyTimeReadClock(¤tTime); + + frameLen = frameLen * 2 + 12 + 22 + 2; //Convert to symbols and add IFS and ACK duration + + if( mPhySeqTimeout > currentTime ) + { + time = mPhySeqTimeout - currentTime; + } + else + { + time = (gPhyTimeMask_c - currentTime + mPhySeqTimeout) & gPhyTimeMask_c; + } + + if( time > 4 ) + { + mPhySeqTimeout = (currentTime + frameLen) & gPhyTimeMask_c; + MCR20Drv_DirectAccessSPIMultiByteWrite( T3CMP_LSB, (uint8_t *)&mPhySeqTimeout, 3); + } + + OSA_ExitCritical(kCriticalDisableInt); + } + +#ifdef MAC_PHY_DEBUG + PLME_SendMessage(&phyLocal[instanceId], gPlme_RxSfdDetectInd_c); + Phy24Task(&phyLocal[instanceId]); +#endif +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that a Sync Loss occured (PLL unlock) +* The Radio is forced to Idle. +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +void Radio_Phy_PlmeSyncLossIndication(instanceId_t instanceId) +{ + PhyPlmeForceTrxOffRequest(); +#ifdef MAC_PHY_DEBUG + PLME_SendMessage(&phyLocal[instanceId], gPlme_SyncLossInd_c); +#endif + Radio_Phy_TimeRxTimeoutIndication(instanceId); +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that a Filter Fail occured +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +void Radio_Phy_PlmeFilterFailRx(instanceId_t instanceId) +{ +#ifdef MAC_PHY_DEBUG + PLME_SendMessage(&phyLocal[instanceId], gPlme_FilterFailInd_c); + Phy24Task(&phyLocal[instanceId]); +#endif +} + +/*! ********************************************************************************* +* \brief This function signals the PHY task that an unexpected Transceiver Reset +* occured and force the TRX to Off +* +* \param[in] instanceId The instance of the PHY +* +********************************************************************************** */ +void Radio_Phy_UnexpectedTransceiverReset(instanceId_t instanceId) +{ + PhyPlmeForceTrxOffRequest(); +#ifdef MAC_PHY_DEBUG + PLME_SendMessage(&phyLocal[instanceId], gPlme_UnexpectedRadioResetInd_c); +#endif + Radio_Phy_TimeRxTimeoutIndication(instanceId); +} + +/*! ********************************************************************************* +* \brief Senf a PLME message to upper layer +* +* \param[in] instanceId The instance of the PHY +* \param[in] msgType The type of message to be sent +* +********************************************************************************** */ +static void PLME_SendMessage(Phy_PhyLocalStruct_t *pPhyStruct, phyMessageId_t msgType) +{ + plmeToMacMessage_t * pMsg = MEM_BufferAlloc(sizeof(plmeToMacMessage_t)); + + if(NULL == pMsg) + { + //panic(0,(uint32_t)PLME_SendMessage,0,msgType); + return; + } + + pMsg->msgType = msgType; + + switch(msgType) + { + case gPlmeCcaCnf_c: + pMsg->msgData.ccaCnf.status = pPhyStruct->channelParams.channelStatus; + break; + + case gPlmeEdCnf_c: + pMsg->msgData.edCnf.status = gPhySuccess_c; + pMsg->msgData.edCnf.energyLeveldB = pPhyStruct->channelParams.energyLeveldB; + pMsg->msgData.edCnf.energyLevel = Phy_GetEnergyLevel(pPhyStruct->channelParams.energyLeveldB); + break; + + default: + /* No aditional info needs to be filled */ + break; + } + + pPhyStruct->PLME_MAC_SapHandler(pMsg, pPhyStruct->currentMacInstance); +} + +/*! ********************************************************************************* +* \brief Senf a PD message to upper layer +* +* \param[in] instanceId The instance of the PHY +* \param[in] msgType The type of message to be sent +* +********************************************************************************** */ +static void PD_SendMessage(Phy_PhyLocalStruct_t *pPhyStruct, phyMessageId_t msgType) +{ + pdDataToMacMessage_t *pMsg; + + if( msgType == gPdDataInd_c ) + { + uint32_t temp; + uint16_t len = pPhyStruct->rxParams.psduLength - 2; //Excluding FCS (2 bytes); + + pMsg = pPhyStruct->rxParams.pRxData; + pPhyStruct->rxParams.pRxData = NULL; + +#if !gUsePBTransferThereshold_d + MCR20Drv_PB_SPIBurstRead( (uint8_t *)(pMsg->msgData.dataInd.pPsdu), len ); +#endif + + pMsg->msgType = gPdDataInd_c; + pMsg->msgData.dataInd.ppduLinkQuality = pPhyStruct->rxParams.linkQuality; + pMsg->msgData.dataInd.psduLength = len; + + pMsg->msgData.dataInd.timeStamp = PhyTime_GetTimestamp(); //current timestamp (64bit) + temp = (uint32_t)(pMsg->msgData.dataInd.timeStamp & gPhyTimeMask_c); //convert to 24bit + pMsg->msgData.dataInd.timeStamp -= (temp - pPhyStruct->rxParams.timeStamp) & gPhyTimeMask_c; +#if !(gMpmIncluded_d) + pPhyStruct->PD_MAC_SapHandler(pMsg, pPhyStruct->currentMacInstance); +#else + { + uint32_t i, bitMask = PhyPpGetPanOfRxPacket(); + + for( i=0; i<gMpmPhyPanRegSets_c; i++ ) + { + if( bitMask & (1 << i) ) + { + bitMask &= ~(1 << i); + pPhyStruct->currentMacInstance = MPM_GetMacInstanceFromRegSet(i); + + /* If the packet passed filtering on muliple PANs, send a copy to each one */ + if( bitMask ) + { + pdDataToMacMessage_t *pDataIndCopy; + + pDataIndCopy = MEM_BufferAlloc(sizeof(pdDataToMacMessage_t) + len); + + if( pDataIndCopy ) + { + FLib_MemCpy(pDataIndCopy, pMsg, sizeof(pdDataToMacMessage_t) + len); + pPhyStruct->PD_MAC_SapHandler(pDataIndCopy, pPhyStruct->currentMacInstance); + } + } + else + { + pPhyStruct->PD_MAC_SapHandler(pMsg, pPhyStruct->currentMacInstance); + break; + } + } + } + } +#endif + } + else + { + pMsg = MEM_BufferAlloc( sizeof(pdDataToMacMessage_t) ); + + if(NULL == pMsg) + { + //panic(0,(uint32_t)PD_SendMessage,0,gPdDataCnf_c); + return; + } + + pMsg->msgType = gPdDataCnf_c; + + if( pPhyStruct->flags & gPhyFlagFramePending_c ) + { + pPhyStruct->flags &= ~(gPhyFlagFramePending_c); + pMsg->msgData.dataCnf.status = gPhyFramePending_c; + } + else + { + pMsg->msgData.dataCnf.status = gPhySuccess_c; + } + + pPhyStruct->PD_MAC_SapHandler(pMsg, pPhyStruct->currentMacInstance); + } +} + +void MSG_InitQueue(macPhyInputQueue_t * pMacPhyQueue) +{ + pMacPhyQueue->msgInIdx = 0; + FLib_MemSet(&pMacPhyQueue->pMsgIn[0], 0x00, gPhyMsgQueueMax_c * sizeof(void*)); +} + +/* Check if a message is pending in a queue. Returns */ +/* TRUE if any pending messages, and FALSE otherwise. */ +bool_t MSG_Pending(macPhyInputQueue_t * pMacPhyQueue) +{ + return (pMacPhyQueue->msgInIdx > 0); +} + +/* Get a message from a queue. Returns NULL if no messages in queue. */ +void * MSG_DeQueue(macPhyInputQueue_t * pMacPhyQueue) +{ + phyMessageHeader_t * pMsgIn = NULL; + uint32_t i = 0; + + if(MSG_Pending(pMacPhyQueue)) + { + pMsgIn = pMacPhyQueue->pMsgIn[0]; + + while(i < pMacPhyQueue->msgInIdx) + { + pMacPhyQueue->pMsgIn[i] = pMacPhyQueue->pMsgIn[i+1]; + i++; + } + + pMacPhyQueue->msgInIdx--; + pMacPhyQueue->pMsgIn[pMacPhyQueue->msgInIdx] = NULL; + } + + return pMsgIn; +} + + +void MSG_Queue(macPhyInputQueue_t * pMacPhyQueue, void * pMsgIn) +{ + if(pMacPhyQueue->msgInIdx < gPhyMsgQueueMax_c) + { + pMacPhyQueue->pMsgIn[pMacPhyQueue->msgInIdx] = pMsgIn; + pMacPhyQueue->msgInIdx++; + } +} + +void MSG_QueueHead(macPhyInputQueue_t * pMacPhyQueue, void * pMsgIn) +{ + uint32_t i = gPhyMsgQueueMax_c - 1; + + if(pMacPhyQueue->msgInIdx < gPhyMsgQueueMax_c) + { + while(i > 0) + { + pMacPhyQueue->pMsgIn[i] = pMacPhyQueue->pMsgIn[i-1]; + i--; + } + pMacPhyQueue->pMsgIn[0] = pMsgIn; + pMacPhyQueue->msgInIdx++; + } +} + +