/*****************************************************************************/ /** * Description: Implementation of physical control functions * * Date: 2021-11-16 00:08 * LastEditTime: 2023-04-23 17:48 * Revisions: Rev 0.2 * History: * [2021-11-16]: Initial version. * [2022-06-18]: New branch for glink control purpose: * -Add poll mode, physical layer will start Tx/Rx procedure * at specific time stamp. * -Add 61/37 beam switch * -Code simplification. * [2023-04-24]: Feature add: * - Read frame type from PL status register. * * Copyright(c) 2021 Beijing Institute of Technology. * Lab of Communication and Networking * ******************************************************************************/ /***************************** Include Files *********************************/ #include #include #include #include "phy_ctrl.h" #include "../util/util.h" #include "../error.h" #ifndef EMULATION #include "xbram.h" #endif /************************** Constant Definitions *****************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ static void Phy_RcdShift(PHY_RCD* rcd, int32_t netxVal); static int32_t Phy_SetSendData(PHY_INST* instPtr, L1_FRAME_TYPE frameType, uint8_t* dataBuff); /**************************** Type Definitions *******************************/ /************************** Variable Definitions *****************************/ /*****************************************************************************/ /** * @brief Setup data will be sent in next slot. * * @param instPtr A pointer to physical layer control instance. * * @return FAILURE Error occurred. * SUCCESS Setting data successful. * ******************************************************************************/ static int32_t Phy_SetSendData(PHY_INST* instPtr, L1_FRAME_TYPE frameType, uint8_t* dataBuff) { ASSERT(instPtr != NULL); ASSERT(dataBuff != NULL); uint32_t frameLen, sendCmd; frameLen = Phy_GetFrameLen(frameType); if (frameLen == L1_FRAME_NONE_LEN) { DBG_ERROR("Invalid frame length.\n"); return EPARAM; } instPtr->sendDataOffset = (TXRXDATA_MAX_LEN >> 1) - instPtr->sendDataOffset; memcpy((uint8_t*)(instPtr->sendDataAddr + instPtr->sendDataOffset), dataBuff, frameLen); sendCmd = frameLen & SEND_DATA_CMD_LEN_MASK; sendCmd |= (instPtr->sendDataOffset << SEND_DATA_CMD_OFFSET_SHIFT) & SEND_DATA_CMD_OFFSET_MASK; // Physical layer start fetching data. PhyWrite(instPtr, SEND_DATA_CMD, sendCmd); return SUCCESS; } /*****************************************************************************/ /** * @brief Check whether a frame was detected. (Do not check if the frame was * deoced.) * * @param instPtr A pointer to physical layer control instance. * * @return true * false * ******************************************************************************/ inline bool Phy_IsFrameDetected(PHY_INST* instPtr) { ASSERT(instPtr != NULL); if(instPtr->isAcq && instPtr->isFrameSync) { return true; } else { return false; } } /*****************************************************************************/ /** * @brief Check whether a frame was received. (Do not check if the frame was * crashed.) * * @param instPtr A pointer to physical layer control instance. * * @return true * false * ******************************************************************************/ inline bool Phy_IsFrameReceived(PHY_INST* instPtr) { ASSERT(instPtr != NULL); if(instPtr->isAcq && instPtr->isFrameSync && instPtr->isDecode) { return true; } else { return false; } } /*****************************************************************************/ /** * @brief Check whether a frame was valid. (if the frame was crashed, it will * be regarded as not valid. * * @param instPtr * * @return true * false * ******************************************************************************/ inline bool Phy_IsFrameValid(PHY_INST* instPtr) { ASSERT(instPtr != NULL); return instPtr->isValid; } /*****************************************************************************/ /** * @brief Get frame type of the frame in receive data buffer (Base on PL Record). * * @param instPtr A pointer to physical layer control instance. * * @return Layer2 frame type. Refer "frame_def.h" * ******************************************************************************/ inline L1_FRAME_TYPE Phy_GetLastRecvFrameType(PHY_INST *instPtr) { ASSERT(instPtr != NULL); if (Phy_IsFrameReceived(instPtr) == false) { return L1_NONE_FRAME; } int32_t frame_type = (PhyRead(instPtr, PHY_MODE_CTRL) & PHY_MODE_CTRL_FRAME_MASK) >> PHY_MODE_CTRL_FRAME_SHIFT; if(frame_type < L1_1M2BPS_5MS_FRAME) return frame_type; else return L1_NONE_FRAME; } /*****************************************************************************/ /** * @brief Get frame type of the frame was sent in last slot. * * @param instPtr A pointer to physical layer control instance. * * @return Layer2 frame type. Refer "frame_def.h" * ******************************************************************************/ inline L1_FRAME_TYPE Phy_GetLastSendFrameType(PHY_INST* instPtr) { ASSERT(instPtr != NULL); if (instPtr->TOR.last != PHY_TOR_TX) { return L1_NONE_FRAME; } return instPtr->frameType.last; } /*****************************************************************************/ /** * @brief Shift l1 status record.(newval->next->curr->last) * * @param instPtr A pointer to physical layer control instance. * * @return NONE. * ******************************************************************************/ static void Phy_RcdShift(PHY_RCD* rcd, int32_t netxVal){ ASSERT(rcd != NULL); rcd->last = rcd->curr; rcd->curr = rcd->next; rcd->next = netxVal; } /*****************************************************************************/ /** * @brief Get corresponding frame length in byte of L1 frame. * * @param frameType * * @return Corresponding frame length * L1_FRAME_NONE_LEN if the frame type code cannot be recognized. * ******************************************************************************/ uint32_t Phy_GetFrameLen(L1_FRAME_TYPE frameType) { switch (frameType) { case L1_2KBPS_20MS_FRAME: return L1_FRAME_2KBPS_20MS_LEN; case L1_2KBPS_100MS_FRAME: return L1_FRAME_2KBPS_100MS_LEN; case L1_10KBPS_10MS_FRAME: return L1_FRAME_10KBPS_10MS_LEN; case L1_10KBPS_20MS_FRAME: return L1_FRAME_10KBPS_20MS_LEN; case L1_40KBPS_20MS_FRAME: return L1_FRAME_40KBPS_20MS_LEN; case L1_40KBPS_10MS_FRAME: return L1_FRAME_40KBPS_10MS_LEN; case L1_200KBPS_5MS_FRAME: return L1_FRAME_200KBPS_5MS_LEN; case L1_1M2BPS_5MS_FRAME: return L1_FRAME_1M2BPS_5MS_LEN; default: return L1_FRAME_NONE_LEN; } } /*****************************************************************************/ /** * @brief Update physical layer status cache. * * @param instPtr A pointer to physical layer control instance. * * @return NONE. * ******************************************************************************/ void Phy_UpdateState(PHY_INST* instPtr) { ASSERT(instPtr != NULL); /* Update Frame Sate. */ uint32_t txrxSate = PhyRead(instPtr, TXRX_STATE); instPtr->isAcq = ((txrxSate & TXRX_STATE_ACQ_MASK) == TXRX_STATE_ACQ_SUCCESS) ? true : false; instPtr->isFrameSync = ((txrxSate & TXRX_STATE_FSYNC_MASK) == TXRX_STATE_FSYNC_SUCCESS) ? true : false; instPtr->isDecode = ((txrxSate & TXRX_STATE_DECODE_MASK) == TXRX_STATE_DECODE_SUCCESS) ? true : false; if (Phy_IsFrameReceived(instPtr)) { instPtr->isValid = ((txrxSate & TXRX_STATE_CRC_MASK) == TXRX_STATE_CRC_OK) ? true : false; } else { instPtr->isValid = false; } } /*****************************************************************************/ /** * @brief Initialize physical layer instance accordingly. * * @param instPtr a pointer to physical instance * @param phyConfig a pointer to cinfiguration staructure. * * @return SUCCESS * ******************************************************************************/ int32_t Phy_InstInit(PHY_INST** instPtr, PHY_CONFIG *phyConfig) { ASSERT(instPtr != NULL); ASSERT(phyConfig != NULL); int32_t Status; *instPtr = (PHY_INST*) malloc(sizeof(PHY_INST)); if ((*instPtr) == NULL) { return EALLOC; } memcpy(&(*instPtr)->phyCofig, phyConfig, sizeof(PHY_CONFIG)); (*instPtr)->isPhyEn = false; (*instPtr)->isAcq = false; (*instPtr)->isFrameSync = false; (*instPtr)->isDecode = false; (*instPtr)->isValid = false; (*instPtr)->isPresetHop = false; (*instPtr)->antConfigOffset = 0; (*instPtr)->sendDataOffset = 0; Phy_AntCoinfoInit(&((*instPtr)->antCoinfoPtr)); memset(&((*instPtr))->TOR, PHY_TOR_SUSPEND, sizeof(PHY_RCD)); memset(&((*instPtr)->frameType), L1_NONE_FRAME, sizeof(PHY_RCD)); memset(&((*instPtr)->antNo), (int32_t)INIT_BEAM_NO, sizeof(PHY_RCD)); memset(&((*instPtr)->beamNo), (int32_t)INIT_ANT_NO, sizeof(PHY_RCD)); memset(&((*instPtr)->beamWd), (int32_t)INIT_ANT_WD, sizeof(PHY_RCD)); #ifndef EMULATION XBram antInfoBram; XBram txFrameBram; XBram rxFrameBram; XBram_Config *ConfigPtr; ConfigPtr = XBram_LookupConfig(phyConfig->antBramId); if (ConfigPtr == NULL) { Status = EDINVAL; goto error; } Status = XBram_CfgInitialize(&antInfoBram, ConfigPtr, ConfigPtr->CtrlBaseAddress); if (Status != SUCCESS) { goto error; } /* * Execute the BRAM driver selftest. */ Status = XBram_SelfTest(&antInfoBram, 0); if (Status != SUCCESS) { goto error; } ConfigPtr = XBram_LookupConfig(phyConfig->txBramId); if (ConfigPtr == NULL) { Status = EDINVAL; goto error; } Status = XBram_CfgInitialize(&txFrameBram, ConfigPtr, ConfigPtr->CtrlBaseAddress); if (Status != SUCCESS) { goto error; } /* * Execute the BRAM driver selftest. */ Status = XBram_SelfTest(&txFrameBram, 0); if (Status != SUCCESS) { goto error; } ConfigPtr = XBram_LookupConfig(phyConfig->rxBramId); if (ConfigPtr == NULL) { Status = EDINVAL; goto error; } Status = XBram_CfgInitialize(&rxFrameBram, ConfigPtr, ConfigPtr->CtrlBaseAddress); if (Status != SUCCESS) { goto error; } /* * Execute the BRAM driver selftest. */ Status = XBram_SelfTest(&rxFrameBram, 0); if (Status != SUCCESS) { goto error; } (*instPtr)->antConfigAddr = antInfoBram.Config.MemBaseAddress; (*instPtr)->recvDataAddr = rxFrameBram.Config.MemBaseAddress; (*instPtr)->sendDataAddr = txFrameBram.Config.MemBaseAddress; #else (*instPtr)->antConfigAddr = (uintptr_t)calloc(ANTCONFIG_MAX_LEN/sizeof(uint64_t), sizeof(uint64_t)); if ((*instPtr)->antConfigAddr == (uintptr_t)NULL) { Status = EALLOC; goto error; } (*instPtr)->recvDataAddr = (uintptr_t)calloc(TXRXDATA_MAX_LEN/sizeof(uint64_t), sizeof(uint64_t)); if ((*instPtr)->recvDataAddr == (uintptr_t)NULL) { Status = EALLOC; goto error; } (*instPtr)->sendDataAddr = (uintptr_t)calloc(TXRXDATA_MAX_LEN/sizeof(uint64_t), sizeof(uint64_t)); if ((*instPtr)->sendDataAddr == (uintptr_t)NULL) { Status = EALLOC; goto error; } #endif return SUCCESS; error: Phy_Destroy(*instPtr); return Status; } /*****************************************************************************/ /** * @brief Destroy physical layer inctance, free allocated memory. * * @param instPtr a pointer to physical instance * * @return NONE * ******************************************************************************/ void Phy_Destroy(PHY_INST* instPtr) { if (instPtr == NULL){ return; } #ifdef EMULATION free((void*)instPtr->antConfigAddr); free((void*)instPtr->recvDataAddr); free((void*)instPtr->sendDataAddr); #endif free(instPtr); } /*****************************************************************************/ /** * @brief Start physical layer * * @param instPtr a pointer to physical instance * * @return NONE * ******************************************************************************/ void Phy_Start(PHY_INST* instPtr) { ASSERT(instPtr != NULL); uint32_t phyMainCtrl = PhyRead(instPtr, PHY_MAIN_CTRL); if((phyMainCtrl & PHY_MAIN_CTRL_EN_MASK) == PHY_MAIN_CTRL_EN_EN) { DBG_WARNING("Physical layer was allready enabled.\n"); } instPtr->isPhyEn = true; // Enable CRC check automatically PhyWrite(instPtr, PHY_MAIN_CTRL, (phyMainCtrl | PHY_MAIN_CTRL_EN_EN)); } /*****************************************************************************/ /** * @brief Halt physical layer operation * * @param instPtr a pointer to physical instance * * @return NONE * ******************************************************************************/ void Phy_Halt(PHY_INST* instPtr) { ASSERT(instPtr != NULL); uint32_t phyMainCtrl = PhyRead(instPtr, PHY_MAIN_CTRL); if((phyMainCtrl & PHY_MAIN_CTRL_EN_MASK) == PHY_MAIN_CTRL_EN_DSBL) { DBG_WARNING("Physical layer was allready halted.\n"); } instPtr->isPhyEn = false; PhyWrite(instPtr, PHY_MAIN_CTRL, (phyMainCtrl & (~PHY_MAIN_CTRL_EN_MASK))); } /*****************************************************************************/ /** * @brief Set physical layer working mode. * * @param instPtr a pointer to physical instance * @param modeCod intened mode code * * @return SUCCESS * other * ******************************************************************************/ int32_t Phy_SetMode(PHY_INST* instPtr, PHY_MODE modeCod) { ASSERT(instPtr != NULL); uint32_t phyMainCtrl = PhyRead(instPtr, PHY_MAIN_CTRL) & ~PHY_MAIN_CTRL_MODE_MASK; switch (modeCod) { case PHY_MODE_NONE: phyMainCtrl |= PHY_MAIN_CTRL_MODE_NONE; break; case PHY_MODE_LISTEN: phyMainCtrl |= PHY_MAIN_CTRL_MODE_LISTEN; break; case PHY_MODE_SCHEDULE: phyMainCtrl |= PHY_MAIN_CTRL_MODE_SCHEDULE; break; case PHY_MODE_PULL: phyMainCtrl |= PHY_MAIN_CTRL_MODE_PULL; break; default: return FAILURE; break; } PhyWrite(instPtr, PHY_MAIN_CTRL, phyMainCtrl); return SUCCESS; } /*****************************************************************************/ /** * @brief Setup next slot operation. * * @param instPtr a pointer to physical instance * @param txrxMode tor type of next slot * @param frameType frame type of next slot * * @return SUCCESS * other * ******************************************************************************/ int32_t Phy_SetupNextSlot(PHY_INST* instPtr, PHY_TOR_TYPE txrxMode, L1_FRAME_TYPE frameType, uint8_t* dataBuff) { ASSERT(instPtr != NULL); int32_t Status; uint32_t phyModeCtrl, hopNum; uint16_t* hopPattern = NULL; // Implement a ping-pong flow, offset always is 0 or half of buffer depth. instPtr->antConfigOffset = (ANTCONFIG_MAX_LEN >> 1) - instPtr->antConfigOffset; uint32_t antConfigAddr = instPtr->antConfigAddr + instPtr->antConfigOffset; instPtr->TOR.next = txrxMode; instPtr->frameType.next = frameType; switch (txrxMode) { case PHY_TOR_SUSPEND: phyModeCtrl = PHY_MODE_CTRL_TOR_SUSPEND; break; case PHY_TOR_RX: phyModeCtrl = PHY_MODE_CTRL_TOR_RX; break; case PHY_TOR_TX: phyModeCtrl = PHY_MODE_CTRL_TOR_TX; break; default: return EPARAM; } switch (frameType) { case L1_2KBPS_20MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_2KBPS_20MS; hopNum = L1_FRAME_2KBPS_20MS_HOPS; hopPattern = hopPattern_10KBPS_10MS; break; case L1_2KBPS_100MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_2KBPS_100MS; hopNum = L1_FRAME_2KBPS_100MS_HOPS; hopPattern = hopPattern_2KBPS_100MS; break; case L1_10KBPS_10MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_10KBPS_10MS; hopNum = L1_FRAME_10KBPS_10MS_HOPS; hopPattern = hopPattern_10KBPS_10MS; break; case L1_10KBPS_20MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_10KBPS_20MS; hopNum = L1_FRAME_10KBPS_20MS_HOPS; hopPattern = hopPattern_10KBPS_20MS; break; case L1_40KBPS_20MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_200KBPS_5MS; hopNum = L1_FRAME_200KBPS_5MS_HOPS; hopPattern = hopPattern_200KBPS_5MS; break; case L1_40KBPS_10MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_40KBPS_10MS; hopNum = L1_FRAME_40KBPS_10MS_HOPS; hopPattern = hopPattern_40KBPS_10MS; break; case L1_200KBPS_5MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_200KBPS_5MS; hopNum = L1_FRAME_200KBPS_5MS_HOPS; hopPattern = hopPattern_200KBPS_5MS; break; case L1_1M2BPS_5MS_FRAME: phyModeCtrl |= PHY_MODE_CTRL_FRAME_1M2BPS_5MS; hopNum = L1_FRAME_1M2BPS_5MS_HOPS; hopPattern = hopPattern_1M2BPS_5MS; break; default: return EPARAM; break; } hopPattern = (instPtr->isPresetHop) ? hopPattern : hopPattern_Config; uint8_t* dataSrcPtr = (uint8_t*)(&(instPtr->antCoinfoPtr)); for (int32_t i = 0; i < hopNum; i++) { instPtr->antCoinfoPtr.antFreq[1] = (uint8_t)(hopPattern[i] & 0x00FF); instPtr->antCoinfoPtr.antFreq[0] = (uint8_t)( (hopPattern[i] >> 8) & 0x00FF); memcpy((uint8_t*) (antConfigAddr + i * sizeof(PHY_ANT_CONFIG)), dataSrcPtr, sizeof(PHY_ANT_CONFIG)); } uint32_t antCtrl = (instPtr->antConfigOffset & ANT_CONFIG_OFFSET_MASK) | ((hopNum << ANT_CONFIG_NUM_SHIFT) & ANT_CONFIG_NUM_MASK) | ((sizeof(PHY_ANT_CONFIG) << ANT_CONFIG_LEN_SHIFT) & ANT_CONFIG_LEN_MASK); /* memcpy((uint8_t*)antConfigDataAddr, hopPattern, hopNum*sizeof(uint16_t)); uint32_t antCtrl = (instPtr->antCoinfigOffset & ANT_CONFIG_OFFSET_MASK) | ((hopNum << ANT_CONFIG_NUM_SHIFT) & ANT_CONFIG_NUM_MASK) | ((sizeof(uint16_t) << ANT_CONFIG_LEN_SHIFT) & ANT_CONFIG_LEN_MASK); */ PhyWrite(instPtr, PHY_MODE_CTRL, phyModeCtrl|PHY_MODE_CTRL_CRC_EN); PhyWrite(instPtr, ANT_CONFIG, antCtrl); // Trigger physical configuration. if(txrxMode == PHY_TOR_TX) { Status = Phy_SetSendData(instPtr, frameType, dataBuff); if(Status != SUCCESS) { DBG_ERROR("Failed to apply send data.\n"); return Status; } } PhyWrite(instPtr, SLOT_CMD, SLOT_CMD_KEY); // Phy statr fetching data. Phy_RcdShift(&(instPtr->TOR),txrxMode); Phy_RcdShift(&(instPtr->frameType),frameType); // TODO: Phy_RcdShift(&(instPtr->antNo), INIT_ANT_NO); Phy_RcdShift(&(instPtr->beamNo), INIT_BEAM_NO); Phy_RcdShift(&(instPtr->beamWd), INIT_ANT_WD); return SUCCESS; } /*****************************************************************************/ /** * @brief Get coarse frequency estimation of last valid frame. * * @param instPtr a pointer to physical instance * * @return frequency estimation * ******************************************************************************/ double Phy_GetCoarseFreqEst(PHY_INST* instPtr) { ASSERT(instPtr != NULL); uint32_t regValue; uint8_t acqFreqIdx; int8_t syncFreqIdx; L1_FRAME_TYPE frameType; double freqEst; frameType = Phy_GetLastRecvFrameType(instPtr); if(frameType > L1_1M2BPS_5MS_FRAME || frameType == L1_NONE_FRAME){ return INFINITY; // FIXME } regValue = PhyRead(instPtr, COASE_FREQEST); acqFreqIdx = (regValue >> COASE_FREQEST_ACQ_SHIFT) && COASE_FREQEST_ACQ_MASK; acqFreqIdx = 80 - acqFreqIdx; syncFreqIdx = (regValue >> COASE_FREQEST_SYNC_SHIFT) && COASE_FREQEST_SYNC_MASK; syncFreqIdx = 8 - syncFreqIdx; if(frameType >= L1_200KBPS_5MS_FRAME) { freqEst = (double)acqFreqIdx*(250e3/4); freqEst += (double)syncFreqIdx*1.5e6/64/128; } else { freqEst = acqFreqIdx*(250e3/4); freqEst += (double)syncFreqIdx*12e6/64/128; } return freqEst; } /*****************************************************************************/ /** * @brief Get the corresponding frequency hopping pattern length of a * specified L1 frame type. * * @param frameType a L1 frame type enumeration. * * @return SUCCESS * FAILURE frame type cannot be recognized * ******************************************************************************/ uint32_t Phy_GetHopLength(L1_FRAME_TYPE frameType){ switch (frameType) { case L1_2KBPS_20MS_FRAME: return L1_FRAME_2KBPS_20MS_HOPS; case L1_2KBPS_100MS_FRAME: return L1_FRAME_2KBPS_100MS_HOPS; case L1_10KBPS_10MS_FRAME: return L1_FRAME_10KBPS_10MS_HOPS; case L1_10KBPS_20MS_FRAME: return L1_FRAME_10KBPS_20MS_HOPS; case L1_40KBPS_20MS_FRAME: return L1_FRAME_40KBPS_20MS_HOPS; case L1_40KBPS_10MS_FRAME: return L1_FRAME_40KBPS_10MS_HOPS; case L1_200KBPS_5MS_FRAME: return L1_FRAME_200KBPS_5MS_HOPS; case L1_1M2BPS_5MS_FRAME: return L1_FRAME_1M2BPS_5MS_HOPS; default: return L1_FRAME_NONE_LEN; } } /*****************************************************************************/ /** * @brief Get the corresponding time compensation value (time interval from * frame start to frame sync) * * @param frameType a L1 frame type enumeration. * * @return SUCCESS * FAILURE frame type cannot be recognized * ******************************************************************************/ uint32_t Phy_GetTimeComp(L1_FRAME_TYPE frameType){ switch (frameType) { case L1_2KBPS_20MS_FRAME: return L1_FRAME_2KBPS_20MS_COMP; case L1_2KBPS_100MS_FRAME: return L1_FRAME_2KBPS_100MS_COMP; case L1_10KBPS_10MS_FRAME: return L1_FRAME_10KBPS_10MS_COMP; case L1_10KBPS_20MS_FRAME: return L1_FRAME_10KBPS_20MS_COMP; case L1_40KBPS_20MS_FRAME: return L1_FRAME_40KBPS_20MS_COMP; case L1_40KBPS_10MS_FRAME: return L1_FRAME_40KBPS_10MS_COMP; case L1_200KBPS_5MS_FRAME: return L1_FRAME_200KBPS_5MS_COMP; case L1_1M2BPS_5MS_FRAME: return L1_FRAME_1M2BPS_5MS_COMP; default: return L1_FRAME_NONE_LEN; } } /*****************************************************************************/ /** * @brief Setup a frequency hopping pattern. * * @param patternBuff a pointer to hopping pattern buffer * @param patternLen a integer indicate the length of hopping pattern. * * @return SUCCESS * FAILURE pattern length exceeds maximum length. * ******************************************************************************/ int32_t Phy_SetHopPattern(void* patternBuff, uint32_t patternLen){ ASSERT(patternBuff != NULL); if(patternLen > L1_FRAME_MAX_HOPS){ return FAILURE; } memcpy(hopPattern_Config, patternBuff, patternLen*sizeof(uint16_t)); return SUCCESS; } /*****************************************************************************/ /** * @brief Setup a specific timer word register in physical controller. * * @param patternBuff a pointer to hopping pattern buffer * @param patternLen a integer indicate the length of hopping pattern. * * @return SUCCESS * FAILURE pattern length exceeds maximum length. * ******************************************************************************/ int32_t Phy_SetTimeWord(PHY_INST* instPtr, const TIME_WORD* tmWord, PHY_TIME_WORD_TYPE tmType){ ASSERT(instPtr != NULL); if(tmWord->frac_part>=PHY_TIME_WORD_L_MAX){ return EPARAM; } switch(tmType){ case TIME_WORD_POLL: PhyWrite(instPtr, POLLTIME_L, tmWord->frac_part); PhyWrite(instPtr, POLLTIME_H, tmWord->int_part); break; case TIME_WORD_LISTEN_TIMEOUT: PhyWrite(instPtr, LISTENTIMEOUT_L, tmWord->frac_part); PhyWrite(instPtr, LISTENTIMEOUT_H, tmWord->int_part); break; default: return EPARAM; } return SUCCESS; } /*****************************************************************************/ /** * @brief Get the frame sync time of last received frame. * * @param instPtr a pointer to physical instance * @param frameSycT a pointer to the frame sync time data buffer. * * @return NONE * ******************************************************************************/ void Phy_GetFrameSyncTimeStamp(PHY_INST* instPtr, TIME_WORD* frameSyncT) { ASSERT(instPtr != NULL); ASSERT(frameSyncT != NULL); frameSyncT->int_part = PhyRead(instPtr, TM_TARGET_H); frameSyncT->frac_part = PhyRead(instPtr, TM_TARGET_L); } /*****************************************************************************/ /** * @brief Get the frame sync time of last received frame. * * @param instPtr a pointer to physical instance * @param slotStart a pointer to the time data buffer. * * @return NONE * ******************************************************************************/ void Phy_GetLastSlotStartTimeStamp(PHY_INST* instPtr, TIME_WORD* slotStart) { ASSERT(instPtr != NULL); ASSERT(slotStart != NULL); slotStart->int_part = PhyRead(instPtr, FSTIME_H); slotStart->frac_part = PhyRead(instPtr, FSTIME_L); } /*****************************************************************************/ /** * @brief Copy ans store the received data, if received data valid. * * @param instPtr a pointer to physical layer control instance. * * @return NONE * ******************************************************************************/ void Phy_PeekRecvData(PHY_INST* instPtr, uint8_t* dataBuff) { ASSERT(instPtr != NULL); ASSERT(dataBuff != NULL); if (instPtr->isValid == false) { return; } uint32_t frameLen, offset; frameLen = (PhyRead(instPtr, RECVDATA_STATE) & RECVDATA_STATE_LEN_MASK) >> RECVDATA_STATE_LEN_SHIFT; offset = (PhyRead(instPtr, RECVDATA_STATE) & RECVDATA_STATE_OFFSET_MASK) >> RECVDATA_STATE_OFFSET_SHIFT; memcpy(dataBuff, (uint8_t*)(instPtr->recvDataAddr + offset), frameLen); } /*****************************************************************************/ /** * @brief Get the received data (if valid), store it to data buffer. * and clear data valid flag. * * @param instPtr a pointer to physical layer control instance. * * @return NONE * ******************************************************************************/ void Phy_RetrieveRecvData(PHY_INST* instPtr, uint8_t* dataBuff) { ASSERT(instPtr != NULL); ASSERT(dataBuff != NULL); if (instPtr->isValid == false) { return; } Phy_RetrievePeekData(instPtr, dataBuff); instPtr->isValid = false; }