Files
datalink_repo/datalink814_ge/src/phy_ctrl/phy_ctrl.c
T

1044 lines
31 KiB
C

/*****************************************************************************/
/**
* 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 <string.h>
#include <stdlib.h>
#include <math.h>
#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 = (L1_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, COASE_FREQEST) & COASE_TYPE_MASK);
switch (frame_type) {
case COASE_TYPE_2KBPS_20MS:
return L1_2KBPS_20MS_FRAME;
case COASE_TYPE_2KBPS_100MS:
return L1_2KBPS_100MS_FRAME;
case COASE_TYPE_10KBPS_10MS:
return L1_10KBPS_10MS_FRAME;
case COASE_TYPE_10KBPS_20MS:
return L1_10KBPS_20MS_FRAME;
case COASE_TYPE_40KBPS_20MS:
return L1_40KBPS_20MS_FRAME;
case COASE_TYPE_40KBPS_10MS:
return L1_40KBPS_10MS_FRAME;
case COASE_TYPE_200KBPS_5MS:
return L1_200KBPS_5MS_FRAME;
case COASE_TYPE_1M2BPS_5MS:
return L1_1M2BPS_5MS_FRAME;
default:
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;
// FIXME: using default value, since physical layer may provide unexpected error value.
instPtr->isAcq = true;
instPtr->isFrameSync = true;
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;
}
instPtr->recvSlotTime.int_part = PhyRead(instPtr, TM_TARGET_H);
instPtr->recvSlotTime.frac_part = PhyRead(instPtr, TM_TARGET_L);
instPtr->recvFsTime.int_part = PhyRead(instPtr, FSTIME_H);
instPtr->recvFsTime.frac_part = PhyRead(instPtr, FSTIME_L);
}
/*****************************************************************************/
/**
* @brief Initialize Physical Layer instance, allocate memory for buffers,
* apply a self test.
*
* @param instPtr a pointer to physical instance
* @param phyConfig a pointer to configuration structure.
*
* @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 = true;
(*instPtr)->recvFsTime.int_part = UINT32_MAX;
(*instPtr)->recvFsTime.frac_part = UINT32_MAX;
(*instPtr)->recvSlotTime.int_part = UINT32_MAX;
(*instPtr)->recvSlotTime.frac_part = UINT32_MAX;
(*instPtr)->antConfigOffset = 0;
(*instPtr)->sendDataOffset = 0;
Phy_AntConfigInit(&((*instPtr)->antConfig));
memset(&((*instPtr))->tor, PHY_TOR_SUSPEND, sizeof(PHY_RCD));
memset(&((*instPtr)->frameType), L1_NONE_FRAME, sizeof(PHY_RCD));
memset(&((*instPtr)->antNo), (int32_t)L1_INIT_BEAM_NO, sizeof(PHY_RCD));
memset(&((*instPtr)->beamNo), (int32_t)L1_INIT_ANT_NO, sizeof(PHY_RCD));
memset(&((*instPtr)->beamWd), (int32_t)L1_INIT_ANT_WD, sizeof(PHY_RCD));
#ifndef EMULATION
XBram_Config *bramConfigPtr;
XBram antConfigBram;
XBram txDataBram;
XBram rxDataBram;
bramConfigPtr = XBram_LookupConfig(phyConfig->antBramId);
if (bramConfigPtr == NULL)
{
Status = EDINVAL;
goto error;
}
Status = XBram_CfgInitialize(&antConfigBram, bramConfigPtr,
bramConfigPtr->CtrlBaseAddress);
if (Status != SUCCESS)
{
goto error;
}
/*
* Execute the BRAM driver selftest.
*/
Status = XBram_SelfTest(&antConfigBram, 0);
if (Status != SUCCESS)
{
goto error;
}
bramConfigPtr = XBram_LookupConfig(phyConfig->txBramId);
if (bramConfigPtr == NULL)
{
Status = EDINVAL;
goto error;
}
Status = XBram_CfgInitialize(&txDataBram, bramConfigPtr,
bramConfigPtr->CtrlBaseAddress);
if (Status != SUCCESS)
{
goto error;
}
/*
* Execute the BRAM driver selftest.
*/
Status = XBram_SelfTest(&txDataBram, 0);
if (Status != SUCCESS)
{
goto error;
}
bramConfigPtr = XBram_LookupConfig(phyConfig->rxBramId);
if (bramConfigPtr == NULL)
{
Status = EDINVAL;
goto error;
}
Status = XBram_CfgInitialize(&rxDataBram, bramConfigPtr,
bramConfigPtr->CtrlBaseAddress);
if (Status != SUCCESS)
{
goto error;
}
/*
* Execute the BRAM driver selftest.
*/
Status = XBram_SelfTest(&rxDataBram, 0);
if (Status != SUCCESS)
{
goto error;
}
(*instPtr)->antConfigAddr = antConfigBram.Config.MemBaseAddress;
(*instPtr)->recvDataAddr = rxDataBram.Config.MemBaseAddress;
(*instPtr)->sendDataAddr = txDataBram.Config.MemBaseAddress;
#else
(*instPtr)->antConfigAddr = (uintptr_t)calloc(L1_ANTCONFIG_MAX_LEN / sizeof(uint64_t), sizeof(uint64_t));
if ((*instPtr)->antConfigAddr == (uintptr_t)NULL)
{
Status = EALLOC;
goto error;
}
(*instPtr)->recvDataAddr = (uintptr_t)calloc(L1_TXRXDATA_MAX_LEN / sizeof(uint64_t), sizeof(uint64_t));
if ((*instPtr)->recvDataAddr == (uintptr_t)NULL)
{
Status = EALLOC;
goto error;
}
(*instPtr)->sendDataAddr = (uintptr_t)calloc(L1_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 already 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;
// Implement a ping-pong flow, offset always is 0 or half of buffer depth.
instPtr->antConfigOffset = (L1_ANTCONFIG_MAX_LEN >> 1) - instPtr->antConfigOffset;
uint32_t antConfigAddr = instPtr->antConfigAddr + instPtr->antConfigOffset;
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;
}
if (instPtr->isPresetHop == false)
{
hopPattern = hopPattern_Config;
}
PhyWrite(instPtr, PHY_MODE_CTRL, phyModeCtrl | PHY_MODE_CTRL_CRC_EN);
uint8_t *dataSrcPtr = (uint8_t *)(&(instPtr->antConfig));
for (int32_t i = 0; i < hopNum; i++)
{
instPtr->antConfig.antFreq[1] = (uint8_t)(hopPattern[i] & 0x00FF);
instPtr->antConfig.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, ANT_CONFIG, antCtrl);
if (txrxMode == PHY_TOR_TX)
{
Status = Phy_SetSendData(instPtr, frameType, dataBuff);
if (Status != SUCCESS)
{
DBG_ERROR("Failed to apply send data.\n");
return Status;
}
}
// Trigger physical configuration.
// Indicate physical layer that all the configurations were done.
PhyWrite(instPtr, SLOT_CMD, SLOT_CMD_KEY);
Phy_RcdShift(&(instPtr->tor), txrxMode);
Phy_RcdShift(&(instPtr->frameType), frameType);
// TODO:
Phy_RcdShift(&(instPtr->antNo), L1_INIT_ANT_NO);
Phy_RcdShift(&(instPtr->beamNo), L1_INIT_BEAM_NO);
Phy_RcdShift(&(instPtr->beamWd), L1_INIT_ANT_WD);
return SUCCESS;
}
/*****************************************************************************/
/**
* @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 32bit unsigned integer (10ns)
*
******************************************************************************/
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 Get frequency estimation of last valid frame.
*
* @param instPtr a pointer to physical instance
*
* @return frequency estimation
*
******************************************************************************/
double Phy_GetFreqEst(PHY_INST *instPtr)
{
ASSERT(instPtr != NULL);
uint32_t coarseReg, fineReg, estAbs;
uint8_t acqFreqIdx;
int8_t syncFreqIdx;
L1_FRAME_TYPE frameType;
double coarse, fine;
frameType = Phy_GetLastRecvFrameType(instPtr);
if (frameType > L1_1M2BPS_5MS_FRAME || frameType <= L1_NONE_FRAME)
{
return INFINITY; // FIXME
}
coarseReg = PhyRead(instPtr, COASE_FREQEST);
acqFreqIdx = (coarseReg & COASE_FREQEST_ACQ_MASK) >> COASE_FREQEST_ACQ_SHIFT;
syncFreqIdx = (coarseReg & COASE_FREQEST_SYNC_MASK) >> COASE_FREQEST_SYNC_SHIFT;
fineReg = PhyRead(instPtr, FINE_FREQEST);
estAbs = fineReg & FINE_FREQEST_VAL_MASK;
if (frameType >= L1_200KBPS_5MS_FRAME)
{
// 1.5M Rc
coarse = (double)(80 - acqFreqIdx) * (31.25e3 / 4);
coarse += (double)syncFreqIdx * 1.5e6 / 64 / 128;
fine = 12e6/2048*((double)estAbs)/8192.0;
}
else
{
// 12M Rc
coarse = (double)(8 - acqFreqIdx) * (250e3 / 4);
coarse += (double)syncFreqIdx * 12e6 / 64 / 128;
fine = 48e6/2048*((double)estAbs)/8192.0;
}
fine = ((fineReg & FINE_FREQEST_SIGN_MASK) == FINE_FREQEST_SIGN_NEG) ?
-fine : fine;
return (coarse + fine);
}
/*****************************************************************************/
/**
* @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_MASK) >> COASE_FREQEST_ACQ_SHIFT;
syncFreqIdx = (regValue & COASE_FREQEST_SYNC_MASK) >> COASE_FREQEST_SYNC_SHIFT;
if (frameType >= L1_200KBPS_5MS_FRAME)
{
// 1.5M Rc
freqEst = (double)(80 - acqFreqIdx) * (31.25e3 / 4);
freqEst += (double)syncFreqIdx * 1.5e6 / 64 / 128;
}
else
{
// 12M Rc
freqEst = (double)(8 - acqFreqIdx) * (250e3 / 4);
freqEst += (double)syncFreqIdx * 12e6 / 64 / 128;
}
return freqEst;
}
/*****************************************************************************/
/**
* @brief Get fine frequency estimation of last valid frame.
*
* @param instPtr a pointer to physical instance
*
* @return frequency estimation
*
******************************************************************************/
double Phy_GetFineFreqEst(PHY_INST *instPtr)
{
uint32_t regValue, estAbs;
double freqEst;
L1_FRAME_TYPE frameType;
frameType = Phy_GetLastRecvFrameType(instPtr);
if (frameType > L1_1M2BPS_5MS_FRAME || frameType <= L1_NONE_FRAME)
{
return INFINITY; // FIXME
}
regValue = PhyRead(instPtr, FINE_FREQEST);
estAbs = regValue & FINE_FREQEST_VAL_MASK;
if (frameType >= L1_200KBPS_5MS_FRAME)
{
// 1.5M Rc
freqEst = 12e6/2048*((double)estAbs)/8192.0;
}
else
{
// 12M Rc
freqEst = 48e6/2048*((double)estAbs)/8192.0;
}
freqEst = ((regValue & FINE_FREQEST_SIGN_MASK) == FINE_FREQEST_SIGN_NEG) ?
-freqEst : freqEst;
return freqEst;
}
/*****************************************************************************/
/**
* @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 instPtr
* @param tmWord
* @param tmType
*
* @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 PHY_TIME_WORD_POLL:
PhyWrite(instPtr, POLLTIME_L, tmWord->frac_part);
PhyWrite(instPtr, POLLTIME_H, tmWord->int_part);
break;
case PHY_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 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, FSTIME_H);
frameSyncT->frac_part = PhyRead(instPtr, FSTIME_L);
}
/*****************************************************************************/
/**
* @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_GetLastReceivedFrameSyncTimeStamp(PHY_INST *instPtr, TIME_WORD *frameSyncT)
{
ASSERT(instPtr != NULL);
ASSERT(frameSyncT != NULL);
memcpy(frameSyncT, &(instPtr->recvFsTime), sizeof(TIME_WORD));
}
/*****************************************************************************/
/**
* @brief Get the slot start 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_GetSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotStart)
{
ASSERT(instPtr != NULL);
ASSERT(slotStart != NULL);
slotStart->int_part = PhyRead(instPtr, TM_TARGET_H);
slotStart->frac_part = PhyRead(instPtr, TM_TARGET_L);
}
/*****************************************************************************/
/**
* @brief Get the slot start time of last frame.
*
* @param instPtr a pointer to physical instance
* @param slotStart a pointer to the time data buffer.
*
* @return NONE
*
******************************************************************************/
void Phy_GetLastReceivedSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotStart)
{
ASSERT(instPtr != NULL);
ASSERT(slotStart != NULL);
memcpy(slotStart, &(instPtr->recvSlotTime), sizeof(TIME_WORD));
}
/*****************************************************************************/
/**
* @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_PeekRecvData(instPtr, dataBuff);
instPtr->isValid = false;
}