forked from gatsby/df_datalink
1353 lines
35 KiB
C
1353 lines
35 KiB
C
/*****************************************************************************/
|
|
/**
|
|
* @file link_layer.c
|
|
* @author FanHao ([email protected])
|
|
* @brief DF Linklayer implementation file.
|
|
* @version 0.1
|
|
* @date 2023-05-06
|
|
*
|
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
|
* Lab of Communication and Network
|
|
*
|
|
******************************************************************************/
|
|
|
|
/**
|
|
* @addtogroup LinkLayer
|
|
* @{
|
|
*/
|
|
|
|
/***************************** Include Files *********************************/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "link_layer.h"
|
|
#include "link_layer_types.h"
|
|
#include "node_list.h"
|
|
#include "msg_def.h"
|
|
#include "error.h"
|
|
#include "common.h"
|
|
#include "util.h"
|
|
#include "circ_queue.h"
|
|
#include "../time_ctrl/time_ctrl.h"
|
|
#ifndef EMULATION
|
|
#include "../config/app_config.h"
|
|
#endif
|
|
/************************** Constant Definitions *****************************/
|
|
#define NET_START_TIME_INFTY UINT32_MAX
|
|
#define LINK_BROCK_THRESHOLD L2_SLOTS_PER_FRAME // 0.5 seconds
|
|
|
|
/************************** Variable Definitions *****************************/
|
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|
/**************************** Type Definitions *******************************/
|
|
/************************** Function Prototypes ******************************/
|
|
static void L2_RcdShift(L2_RCD *rcd, uint32_t netxVal);
|
|
static void UpdateMainSate(L2_INST *instPtr, L2_NODE_STATE newSate);
|
|
static void L2_SetSlotNum(L2_INST *instPtr, uint32_t newSlotNum);
|
|
static void L2_SetFrameNum(L2_INST *instPtr, uint32_t newFrameNum);
|
|
static void L2_UpdateSlotNum(L2_INST *instPtr);
|
|
static void L2_DataAvailUpdate(L2_INST *instPtr, bool status);
|
|
static void L2_FrameStateUpdate(L2_INST *instPtr);
|
|
|
|
/**
|
|
* @brief Shift L2 status record.(newval->next->curr->last)
|
|
*/
|
|
inline void L2_RcdShift(L2_RCD *rcd, uint32_t netxVal)
|
|
{
|
|
ASSERT(rcd != NULL);
|
|
rcd->last = rcd->curr;
|
|
rcd->curr = rcd->next;
|
|
rcd->next = netxVal;
|
|
}
|
|
|
|
/**
|
|
* @brief helper function to update linklayer state
|
|
*/
|
|
static inline void UpdateMainSate(L2_INST *instPtr, L2_NODE_STATE newSate)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
DBG_INFO("MainStateUpdate: %" PRId8 " -> %" PRId8 "\n", instPtr->mainState, newSate);
|
|
instPtr->nextState = newSate;
|
|
}
|
|
|
|
/**
|
|
* @brief helper function to set slot number.
|
|
*/
|
|
static void L2_SetSlotNum(L2_INST *instPtr, uint32_t newSlotNum)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
DBG_INFO("Set new slot number to %" PRIu32 "\n", newSlotNum);
|
|
instPtr->slotNum.next = newSlotNum;
|
|
}
|
|
|
|
/**
|
|
* @brief helper function to set frame number
|
|
*/
|
|
static void L2_SetFrameNum(L2_INST *instPtr, uint32_t newFrameNum)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
DBG_INFO("Set new frame number to %" PRIu32 "\n", newFrameNum);
|
|
instPtr->frameNum.next = newFrameNum;
|
|
}
|
|
|
|
/**
|
|
* @brief Update frame number
|
|
*/
|
|
static inline void L2_UpdateSlotNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
uint32_t slotCnt;
|
|
// Shift record
|
|
L2_RcdShift(&(instPtr->frameNum), instPtr->frameNum.next);
|
|
L2_RcdShift(&(instPtr->slotNum), instPtr->slotNum.next);
|
|
|
|
// FIXME: Consider time wrapping
|
|
// Compute and set new slot and frame num
|
|
slotCnt = TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr) + 1;
|
|
instPtr->frameNum.next = slotCnt / L2_SLOTS_PER_FRAME - instPtr->netStartTime;
|
|
instPtr->slotNum.next = slotCnt % L2_SLOTS_PER_FRAME;
|
|
}
|
|
|
|
/**
|
|
* @brief Update l2 frame buffer state
|
|
* infer that if there is a new valid l2 frame up.
|
|
*/
|
|
static inline void L2_DataAvailUpdate(L2_INST *instPtr, bool status)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
instPtr->dataAvail = status;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Update L2 frame state, check if there is any valid L2 frame data in
|
|
* data buffer, update receive frame status.
|
|
*
|
|
* @param instPtr a pointer to linklayer instance
|
|
*
|
|
* @return NONE.
|
|
*
|
|
******************************************************************************/
|
|
static void L2_FrameStateUpdate(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
|
bool isValid;
|
|
isValid = false;
|
|
// Update frame state.
|
|
if (Phy_IsFrameValid(phyRef) == false)
|
|
{
|
|
L2_DataAvailUpdate(instPtr, false);
|
|
}
|
|
else
|
|
{
|
|
DBG_INFO("A frame received, checking data validation...\n");
|
|
DBG_INFO("Last frame type is: %" PRId32 ".\n", instPtr->frame.last);
|
|
Phy_RetrieveRecvData(phyRef, instPtr->recvPktData);
|
|
instPtr->log.frameRecv++;
|
|
|
|
L2_MSG_COMMON *msg = (L2_MSG_COMMON *) instPtr->recvPktData;
|
|
L2_FRAME_TYPE recvType = msg->msgType;
|
|
|
|
// Update frame state.
|
|
switch (recvType)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
isValid = L2_CrcCheck(instPtr->recvPktData, L2_GetFrameLen(L2_FRAME_ADV, L2_SVC_NONE), L2_CRC8_31);
|
|
instPtr->log.advRecvCnt++;
|
|
instPtr->log.advCorrectCnt = isValid ? instPtr->log.advCorrectCnt + 1 : instPtr->log.advCorrectCnt;
|
|
break;
|
|
case L2_FRAME_ACK:
|
|
isValid = L2_CrcCheck(instPtr->recvPktData, L2_GetFrameLen(L2_FRAME_ACK, L2_SVC_NONE), L2_CRC8_31);
|
|
instPtr->log.ackRecvCnt++;
|
|
instPtr->log.ackCorrectCnt = isValid ? instPtr->log.ackCorrectCnt + 1 : instPtr->log.ackCorrectCnt;
|
|
break;
|
|
case L2_FRAME_DIS:
|
|
isValid = L2_CrcCheck(instPtr->recvPktData, L2_GetFrameLen(L2_FRAME_DIS, L2_SVC_NONE), L2_CRC8_31);
|
|
instPtr->log.disRecvCnt++;
|
|
instPtr->log.disCorrectCnt = isValid ? instPtr->log.disCorrectCnt + 1 : instPtr->log.disCorrectCnt;
|
|
break;
|
|
case L2_FRAME_MNG:
|
|
isValid = L2_CrcCheck(instPtr->recvPktData, L2_GetFrameLen(L2_FRAME_MNG, L2_SVC_NONE), L2_CRC8_31);
|
|
instPtr->log.mngRecvCnt++;
|
|
instPtr->log.mngCorrectCnt = isValid ? instPtr->log.mngCorrectCnt + 1 : instPtr->log.mngCorrectCnt;
|
|
break;
|
|
case L2_FRAME_RTT:
|
|
isValid = L2_CrcCheck(instPtr->recvPktData, L2_GetFrameLen(L2_FRAME_RTT, L2_SVC_NONE), L2_CRC8_31);
|
|
instPtr->log.rttRecvCnt++;
|
|
instPtr->log.rttCorrectCnt = isValid ? instPtr->log.rttCorrectCnt + 1 : instPtr->log.rttCorrectCnt;
|
|
break;
|
|
case L2_FRAME_SVC:
|
|
#ifndef DATALINK_ENABLE_BERTEST
|
|
isValid = L2_CrcCheck(instPtr->recvPktData, L2_GetFrameLen(L2_FRAME_SVC, instPtr->config.serviceRate), L2_CRC8_31);
|
|
#else
|
|
isValid = true;
|
|
#endif
|
|
instPtr->log.svcRecvCnt++;
|
|
instPtr->log.svcCorrectCnt = isValid ? instPtr->log.svcCorrectCnt + 1 : instPtr->log.svcCorrectCnt;
|
|
break;
|
|
|
|
default:
|
|
isValid = false;
|
|
break;
|
|
}
|
|
if (isValid)
|
|
{
|
|
instPtr->log.frameCorrect++;
|
|
L2_DataAvailUpdate(instPtr, true);
|
|
}
|
|
else
|
|
{
|
|
L2_DataAvailUpdate(instPtr, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @addtogroup LinkLayer_Utility
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Get the current node ID.
|
|
*/
|
|
inline uint8_t L2_GetNodeId(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->myInfo.nodeId;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the current cluster ID.
|
|
*/
|
|
inline uint8_t L2_GetClusterId(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->myInfo.clustId;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the head node ID.
|
|
*/
|
|
uint8_t L2_GetHeadId(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->myInfo.headId;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the current node type.
|
|
*/
|
|
inline L2_NODE_TYPE L2_GetNodeType(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->myInfo.nodeType;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the current linklayer state.
|
|
*/
|
|
inline L2_NODE_STATE L2_GetMainState(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->mainState;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if there is a valid l2 frame.
|
|
*/
|
|
inline bool L2_isStarted(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->isEnable;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if there is a valid l2 frame.
|
|
*/
|
|
inline bool L2_isDataAvail(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->dataAvail;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if node is connected to the network
|
|
*/
|
|
inline bool L2_isCxn2Net(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->cxn2Net;
|
|
}
|
|
|
|
/**
|
|
* @brief Get corresponding frame length in byte of L2 frame.
|
|
*/
|
|
inline uint32_t L2_GetFrameLen(L2_FRAME_TYPE l2FrameType, L2_SVC_RATE l2SvcRate)
|
|
{
|
|
return Phy_GetFrameLen(L2_L2frame2L1frame(l2FrameType, l2SvcRate));
|
|
}
|
|
|
|
/**
|
|
* @brief Get last frame number.
|
|
*/
|
|
inline uint32_t L2_GetLastFrameNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->frameNum.last;
|
|
}
|
|
|
|
/**
|
|
* @brief Get last slot number.
|
|
*/
|
|
inline uint32_t L2_GetLastSlotNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->slotNum.last;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the frame type of last slot.
|
|
*/
|
|
inline L2_FRAME_TYPE L2_GetLastFrameType(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->frame.last;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the tx/rx state of last slot.
|
|
*/
|
|
inline L2_TOR_TYPE L2_GetLastTor(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->tor.last;
|
|
}
|
|
|
|
/**
|
|
* @brief Get current frame number.
|
|
*/
|
|
inline uint32_t L2_GetCurrentFrameNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->frameNum.curr;
|
|
}
|
|
|
|
/**
|
|
* @brief Get current slot number.
|
|
*/
|
|
inline uint32_t L2_GetCurrentSlotNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->slotNum.curr;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the frame type of current slot.
|
|
*/
|
|
inline L2_FRAME_TYPE L2_GetCurrentFrameType(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->frame.curr;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the tx/rx state of current slot.
|
|
*/
|
|
inline L2_TOR_TYPE L2_GetCurrentTor(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->tor.curr;
|
|
}
|
|
|
|
/**
|
|
* @brief Get next frame number.
|
|
*/
|
|
inline uint32_t L2_GetNextFrameNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->frameNum.next;
|
|
}
|
|
|
|
/**
|
|
* @brief Get next slot number.
|
|
*/
|
|
inline uint32_t L2_GetNextSlotNum(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->slotNum.next;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the frame type of next slot.
|
|
*/
|
|
inline L2_FRAME_TYPE L2_GetNextFrameType(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->frame.next;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the tx/rx state of next slot.
|
|
*/
|
|
inline L2_TOR_TYPE L2_GetNextTor(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->tor.next;
|
|
}
|
|
|
|
/**
|
|
* @brief Get service rate of the node.
|
|
*/
|
|
inline L2_SVC_RATE L2_GetServiceRate(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
return instPtr->config.serviceRate;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Convert L2 frame type to L1 frame type
|
|
*
|
|
* @param l2Frame
|
|
* @param l2SvcRate
|
|
*
|
|
* @return L1 frame type.
|
|
*
|
|
******************************************************************************/
|
|
L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame, L2_SVC_RATE l2SvcRate)
|
|
{
|
|
switch (l2Frame)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
return L1_FRAME_ADV_24MS;
|
|
case L2_FRAME_ACK:
|
|
return L1_FRAME_ACK_8MS;
|
|
case L2_FRAME_DIS:
|
|
case L2_FRAME_MNG:
|
|
case L2_FRAME_RTT:
|
|
return L1_FRAME_128KBPS_4MS;
|
|
case L2_FRAME_SVC:
|
|
switch (l2SvcRate)
|
|
{
|
|
case L2_SVC_128K:
|
|
return L1_FRAME_128KBPS_4MS;
|
|
case L2_SVC_512K:
|
|
return L1_FRAME_512KBPS_4MS;
|
|
case L2_SVC_2M:
|
|
return L1_FRAME_2MBPS_4MS;
|
|
default:
|
|
return L1_FRAME_NONE;
|
|
}
|
|
default:
|
|
return L1_FRAME_NONE;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Get L2 service packet length based on service rate
|
|
*
|
|
* @param l2SvcRate
|
|
*
|
|
* @return Packet length.
|
|
*
|
|
******************************************************************************/
|
|
size_t L2_GetSvcPacketLen(L2_SVC_RATE l2SvcRate)
|
|
{
|
|
switch (l2SvcRate)
|
|
{
|
|
case L2_SVC_128K:
|
|
return sizeof(L2_MSG_SVC_128K);
|
|
case L2_SVC_512K:
|
|
return sizeof(L2_MSG_SVC_512K);
|
|
case L2_SVC_2M:
|
|
return sizeof(L2_MSG_SVC_2M);
|
|
default:
|
|
DBG_ERROR("Unsupported service rate: %" PRId8 ".\n", l2SvcRate);
|
|
return EPARAM;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Get L2 service payload length based on service rate
|
|
*
|
|
* @param l2SvcRate
|
|
*
|
|
* @return Payload length.
|
|
*
|
|
******************************************************************************/
|
|
size_t L2_GetSvcPayloadLen(L2_SVC_RATE l2SvcRate)
|
|
{
|
|
switch (l2SvcRate)
|
|
{
|
|
case L2_SVC_128K:
|
|
return L2_PAYLOAD_LEN_SVC_128K;
|
|
case L2_SVC_512K:
|
|
return L2_PAYLOAD_LEN_SVC_512K;
|
|
case L2_SVC_2M:
|
|
return L2_PAYLOAD_LEN_SVC_2M;
|
|
default:
|
|
DBG_ERROR("Unsupported service rate: %" PRId8 ".\n", l2SvcRate);
|
|
return EPARAM;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Convert antenna broadcast id to antenna index
|
|
*
|
|
* @param antId
|
|
*
|
|
* @return Physical antenna index.
|
|
*
|
|
******************************************************************************/
|
|
PHY_ANT_INDEX L2_AntId2AntIndex(uint8_t antId)
|
|
{
|
|
switch (antId)
|
|
{
|
|
case L2_BROADCAST_ID1:
|
|
return PHY_ANT_INDEX_1;
|
|
case L2_BROADCAST_ID2:
|
|
return PHY_ANT_INDEX_2;
|
|
case L2_BROADCAST_ID3:
|
|
return PHY_ANT_INDEX_3;
|
|
default:
|
|
return PHY_ANT_INDEX_NONE;
|
|
}
|
|
}
|
|
|
|
/** @} LinkLayer_Utility*/
|
|
|
|
/**
|
|
* @defgroup LinkLayer_Main
|
|
* @{
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Initialize link layer fsm instance, allocate memory to storage fsm
|
|
* data. Apply the default values to fsm.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
* @param config a pointer to configurations
|
|
*
|
|
* @return SUCCESS
|
|
* Other error code.
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_Init(L2_INST **instPtr, const L2_CONFIG *config)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
ASSERT(config != NULL);
|
|
|
|
int32_t Status;
|
|
|
|
if (config->phyInstPtr == NULL)
|
|
{
|
|
return EDINVAL;
|
|
}
|
|
if (config->tmcInstPtr == NULL)
|
|
{
|
|
return EDINVAL;
|
|
}
|
|
(*instPtr) = (L2_INST *)malloc(sizeof(L2_INST));
|
|
if (*instPtr == NULL)
|
|
{
|
|
DBG_ERROR("Allocate memory for L2_InstPtr failed.\n");
|
|
return ENOMEM;
|
|
}
|
|
|
|
// Clear random content
|
|
memset(*instPtr, 0x00, sizeof(L2_INST));
|
|
(*instPtr)->sendPktData = NULL;
|
|
(*instPtr)->recvPktData = NULL;
|
|
(*instPtr)->schdEventPool = NULL;
|
|
(*instPtr)->nodeList = NULL;
|
|
(*instPtr)->scanFSM = NULL;
|
|
(*instPtr)->serviceFSM = NULL;
|
|
memcpy(&((*instPtr)->config), config, sizeof(L2_CONFIG));
|
|
|
|
// Packet buffer
|
|
(*instPtr)->sendPktData = calloc(L2_PACK_LEN_MAX / sizeof(uint64_t), sizeof(uint64_t));
|
|
if ((*instPtr)->sendPktData == NULL)
|
|
{
|
|
DBG_ERROR("Allocate memory for sendPktData failed.\n");
|
|
Linklayer_Destroy(*instPtr);
|
|
return ENOMEM;
|
|
}
|
|
(*instPtr)->recvPktData = calloc(L2_PACK_LEN_MAX / sizeof(uint64_t), sizeof(uint64_t));
|
|
if ((*instPtr)->recvPktData == NULL)
|
|
{
|
|
DBG_ERROR("Allocate memory for recvPktData failed.\n");
|
|
Linklayer_Destroy(*instPtr);
|
|
return ENOMEM;
|
|
}
|
|
// Reset basic info
|
|
(*instPtr)->netStartTime = NET_START_TIME_INFTY;
|
|
(*instPtr)->rtneConfig.last = NULL;
|
|
(*instPtr)->rtneConfig.curr = NULL;
|
|
(*instPtr)->rtneConfig.next = NULL;
|
|
(*instPtr)->isEnable = false;
|
|
(*instPtr)->cxn2Net = (config->myType == L2_NODE_HEAD) ? true : false;
|
|
(*instPtr)->dataAvail = false;
|
|
(*instPtr)->frameNum.last = 0;
|
|
(*instPtr)->frameNum.curr = 0;
|
|
(*instPtr)->frameNum.next = 0;
|
|
(*instPtr)->slotNum.last = 0;
|
|
(*instPtr)->slotNum.curr = 0;
|
|
(*instPtr)->slotNum.next = 0;
|
|
(*instPtr)->frame.last = L2_FRAME_NONE;
|
|
(*instPtr)->frame.curr = L2_FRAME_NONE;
|
|
(*instPtr)->frame.next = L2_FRAME_NONE;
|
|
(*instPtr)->tor.last = L2_TOR_SUSPEND;
|
|
(*instPtr)->tor.curr = L2_TOR_SUSPEND;
|
|
(*instPtr)->tor.next = L2_TOR_SUSPEND;
|
|
(*instPtr)->rtneConfig.rtneTable = initTable;
|
|
(*instPtr)->rtneConfig.rtnePrd = ARRAY_SIZE(initTable);
|
|
(*instPtr)->mainState = L2_INIT_STATE;
|
|
(*instPtr)->nextState = L2_INIT_STATE;
|
|
(*instPtr)->myInfo.nodeId = config->myId;
|
|
(*instPtr)->myInfo.clustId = config->clustId;
|
|
(*instPtr)->myInfo.headId = config->headId;
|
|
(*instPtr)->myInfo.nodeType = config->myType;
|
|
(*instPtr)->myInfo.pos.x = 0;
|
|
(*instPtr)->myInfo.pos.y = 0;
|
|
(*instPtr)->myInfo.pos.z = 0;
|
|
(*instPtr)->myInfo.speed.x = 0;
|
|
(*instPtr)->myInfo.speed.y = 0;
|
|
(*instPtr)->myInfo.speed.z = 0;
|
|
(*instPtr)->schdEventPool = NULL;
|
|
(*instPtr)->nodeList = NULL;
|
|
|
|
Status = L2_CreateSchedEventPool(&((*instPtr)->schdEventPool));
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("L2_CreateSchedEventPool runs failed, with error code: %" PRId32 ".\n", Status);
|
|
Linklayer_Destroy(*instPtr);
|
|
return Status;
|
|
}
|
|
|
|
Status = L2_NodeList_Init(&((*instPtr)->nodeList));
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("NodeList_Init runs failed, with error code: %" PRId32 ".\n", Status);
|
|
Linklayer_Destroy(*instPtr);
|
|
return Status;
|
|
}
|
|
|
|
Status = L2_Scan_Init(&((*instPtr)->scanFSM));
|
|
if (Status != SUCCESS)
|
|
{
|
|
Linklayer_Destroy(*instPtr);
|
|
return Status;
|
|
}
|
|
|
|
Status = L2_Service_Init(&((*instPtr)->serviceFSM));
|
|
if (Status != SUCCESS)
|
|
{
|
|
Linklayer_Destroy(*instPtr);
|
|
return Status;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Reconfigure link layer instance, reset all segment and reconfigure
|
|
* accordingly.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
* @param config a pointer to configurations
|
|
*
|
|
* @return SUCCESS
|
|
* Other error code.
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_Reconfig(L2_INST *instPtr, const L2_CONFIG *config)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
ASSERT(config != NULL);
|
|
|
|
if (config->phyInstPtr == NULL)
|
|
{
|
|
return EDINVAL;
|
|
}
|
|
if (config->tmcInstPtr == NULL)
|
|
{
|
|
return EDINVAL;
|
|
}
|
|
memcpy(&(instPtr->config), config, sizeof(L2_CONFIG));
|
|
|
|
// Reset basic info
|
|
memset(&(instPtr->log), 0x00, sizeof(L2_LOG));
|
|
instPtr->netStartTime = UINT32_MAX;
|
|
instPtr->rtneConfig.last = NULL;
|
|
instPtr->rtneConfig.curr = NULL;
|
|
instPtr->rtneConfig.next = NULL;
|
|
instPtr->cxn2Net = (config->myType == L2_NODE_HEAD) ? true : false;
|
|
instPtr->dataAvail = false;
|
|
instPtr->frameNum.last = 0;
|
|
instPtr->frameNum.curr = 0;
|
|
instPtr->frameNum.next = 0;
|
|
instPtr->slotNum.last = 0;
|
|
instPtr->slotNum.curr = 0;
|
|
instPtr->slotNum.next = 0;
|
|
instPtr->frame.last = L2_FRAME_NONE;
|
|
instPtr->frame.curr = L2_FRAME_NONE;
|
|
instPtr->frame.next = L2_FRAME_NONE;
|
|
instPtr->tor.last = L2_TOR_SUSPEND;
|
|
instPtr->tor.curr = L2_TOR_SUSPEND;
|
|
instPtr->tor.next = L2_TOR_SUSPEND;
|
|
instPtr->rtneConfig.rtneTable = initTable;
|
|
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(initTable);
|
|
instPtr->mainState = L2_INIT_STATE;
|
|
instPtr->nextState = L2_INIT_STATE;
|
|
instPtr->myInfo.nodeId = config->myId;
|
|
instPtr->myInfo.clustId = config->clustId;
|
|
instPtr->myInfo.headId = config->headId;
|
|
instPtr->myInfo.nodeType = config->myType;
|
|
instPtr->myInfo.pos.x = 0;
|
|
instPtr->myInfo.pos.y = 0;
|
|
instPtr->myInfo.pos.z = 0;
|
|
instPtr->myInfo.speed.x = 0;
|
|
instPtr->myInfo.speed.y = 0;
|
|
instPtr->myInfo.speed.z = 0;
|
|
|
|
// Reset according instance
|
|
L2_ClearSchedEventPool(instPtr->schdEventPool);
|
|
L2_NodeList_Clear(instPtr->nodeList);
|
|
L2_Scan_Reset(instPtr->scanFSM);
|
|
L2_Service_Reset(instPtr->serviceFSM);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Completely destroy link layer instance, free all allocated memory.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
*
|
|
* @return NONE
|
|
*
|
|
******************************************************************************/
|
|
void Linklayer_Destroy(L2_INST *instPtr)
|
|
{
|
|
if (instPtr == NULL)
|
|
{
|
|
return;
|
|
}
|
|
free(instPtr->sendPktData);
|
|
free(instPtr->recvPktData);
|
|
// Destroy FSMs and nodeList
|
|
L2_DestroySchedEventPool(instPtr->schdEventPool);
|
|
L2_NodeList_Destroy(instPtr->nodeList);
|
|
L2_Scan_Destroy(instPtr->scanFSM);
|
|
L2_Service_Destroy(instPtr->serviceFSM);
|
|
free(instPtr);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Start link layer processing.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
*
|
|
* @return NONE
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_Start(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
// Set netStartTime at first call, i.e. at the beginning of next time unit.
|
|
if (instPtr->netStartTime == NET_START_TIME_INFTY)
|
|
{
|
|
instPtr->netStartTime = TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr) / L2_SLOTS_PER_FRAME + 1;
|
|
}
|
|
instPtr->isEnable = true;
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Halt link layer.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
*
|
|
* @return NONE
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_Halt(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
instPtr->isEnable = false;
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Handle l2 event called by other model.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
* @param l2Event
|
|
*
|
|
* @return SUCCESS - Event has been successfully handled.
|
|
* FAIL - Event cannot be recognized or error occurred while process.
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_EventHandler(L2_INST *instPtr, const L2_EVENT *l2Event)
|
|
{
|
|
switch (l2Event->event)
|
|
{
|
|
case L2_EV_SET_FRAME_NUM:
|
|
{
|
|
DBG_INFO("Event L2_EV_FRAME_NO_UPDATE asserted....\n");
|
|
L2_SetFrameNum(instPtr, *((uint32_t *)l2Event->msg));
|
|
break;
|
|
}
|
|
case L2_EV_SET_SLOT_NUM:
|
|
{
|
|
DBG_INFO("Event L2_EV_SLOT_NO_UPDATE asserted....\n");
|
|
L2_SetSlotNum(instPtr, *((uint32_t *)l2Event->msg));
|
|
break;
|
|
}
|
|
case L2_EV_MAIN_STATE_UPDATE:
|
|
{
|
|
DBG_INFO("Event L2_EV_MAIN_STATE_UPDATE asserted....\n");
|
|
UpdateMainSate(instPtr, *((L2_NODE_STATE *)l2Event->msg));
|
|
break;
|
|
}
|
|
case L2_EV_SCAN_PROC_DONE:
|
|
{
|
|
DBG_INFO("Event L2_EV_SCAN_PROC_DONE asserted....\n");
|
|
break;
|
|
}
|
|
case L2_EV_NET_ADV_UPDATE:
|
|
{
|
|
DBG_INFO("Event L2_EV_NET_ADV_UPDATE asserted....\n");
|
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
|
{
|
|
instPtr->netStartTime = *((uint32_t *)l2Event->msg);
|
|
}
|
|
else
|
|
{
|
|
DBG_WARNING("Invalid call from head node.");
|
|
}
|
|
break;
|
|
}
|
|
case L2_EV_NET_SETUP_DONE:
|
|
{
|
|
DBG_INFO("Event L2_EV_NET_SETUP_DONE asserted....\n");
|
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
|
{
|
|
instPtr->cxn2Net = true;
|
|
UpdateMainSate(instPtr, L2_NORMAL_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case L2_EV_TIME_SYNC:
|
|
{
|
|
DBG_INFO("Event L2_EV_TIME_SYNC asserted....\n");
|
|
break;
|
|
}
|
|
case L2_EV_LOST_CXN:
|
|
{
|
|
DBG_INFO("Event L2_EV_LOST_CXN asserted....\n");
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
|
{
|
|
DBG_ERROR("Illegal event, only None_Head node can assert L2_EV_LOST_CXN.\n");
|
|
break;
|
|
}
|
|
DBG_WARNING("Lost connection with head node [%" PRId8 "].\n", L2_GetHeadId(instPtr));
|
|
L2_Scan_Reset(instPtr->scanFSM);
|
|
L2_Service_Reset(instPtr->serviceFSM);
|
|
instPtr->cxn2Net = false;
|
|
UpdateMainSate(instPtr, L2_INIT_STATE);
|
|
instPtr->log.reconnectCnt++;
|
|
break;
|
|
}
|
|
case L2_EV_LOST_NODE:
|
|
{
|
|
DBG_INFO("Event L2_EV_LOST_NODE asserted....\n");
|
|
L2_Scan_Reset(instPtr->scanFSM);
|
|
L2_Service_Reset(instPtr->serviceFSM);
|
|
UpdateMainSate(instPtr, L2_INIT_STATE);
|
|
// Log reconnect
|
|
instPtr->log.reconnectCnt++;
|
|
break;
|
|
}
|
|
case L2_ROUTINE_FINISH:
|
|
{
|
|
DBG_INFO("Event L2_ROUTINE_FINISH asserted....\n");
|
|
if (instPtr->nextState == L2_INIT_STATE)
|
|
{
|
|
// Reset scan net FMS for next scan process.
|
|
L2_Scan_Reset(instPtr->scanFSM);
|
|
UpdateMainSate(instPtr, L2_INIT_STATE);
|
|
instPtr->rtneConfig.rtneTable = initTable;
|
|
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(initTable);
|
|
}
|
|
else if (instPtr->nextState == L2_NORMAL_STATE)
|
|
{
|
|
UpdateMainSate(instPtr, L2_NORMAL_STATE);
|
|
instPtr->rtneConfig.rtneTable = normalTable[L2_DEFAULT_NORMAL_TABLE];
|
|
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable[L2_DEFAULT_NORMAL_TABLE]);
|
|
}
|
|
else
|
|
{
|
|
DBG_WARNING("Unsupported routine state [%" PRId8 "], "
|
|
"Continue with previous routine table.\n", instPtr->nextState);
|
|
}
|
|
break;
|
|
}
|
|
case L2_ROUTINE_UPDATE:
|
|
{
|
|
DBG_INFO("Event L2_ROUTINE_UPDATE asserted....\n");
|
|
L2_RTNE_CONFIG *newRtneConfig = (L2_RTNE_CONFIG *)l2Event->msg;
|
|
instPtr->rtneConfig.rtneTable = newRtneConfig->rtneTable;
|
|
instPtr->rtneConfig.rtnePrd = newRtneConfig->rtnePrd;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
DBG_WARNING("UNKNOWN Event %" PRId8 " asserted.\n", l2Event->event);
|
|
break;
|
|
}
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Handle l2 packet correctly received.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
*
|
|
* @return Status code.
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_PktHandler(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
int32_t Status;
|
|
|
|
if (instPtr->dataAvail == false)
|
|
{
|
|
return FAILURE;
|
|
}
|
|
|
|
L2_MSG_COMMON *msg = (L2_MSG_COMMON *) instPtr->recvPktData;
|
|
L2_FRAME_TYPE frameType = msg->msgType;
|
|
|
|
switch (frameType)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
case L2_FRAME_ACK:
|
|
Status = L2_Scan_PktHandler(instPtr, instPtr->recvPktData);
|
|
break;
|
|
case L2_FRAME_DIS:
|
|
case L2_FRAME_MNG:
|
|
case L2_FRAME_RTT:
|
|
case L2_FRAME_SVC:
|
|
Status = L2_Service_PktHandler(instPtr, instPtr->recvPktData);
|
|
break;
|
|
default:
|
|
DBG_WARNING("L2FrameHandler: UNKNOWN L2-FrameType %" PRId8 "\n", frameType);
|
|
Status = FAILURE;
|
|
break;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* @brief Utility function to update node ttl.
|
|
*/
|
|
static int32_t IntcNodeTTL(NODE_ENTRY *node, const void *param)
|
|
{
|
|
ASSERT(node != NULL);
|
|
node->ttlCnt += *((uint32_t *)param);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Utility function to check connection to node is still valid.
|
|
*/
|
|
#ifdef DATALINK_ENABLE_AUTORECONNECT
|
|
static bool IsNodeConnected(NODE_ENTRY *node)
|
|
{
|
|
ASSERT(node != NULL);
|
|
DBG_INFO("Node: %" PRIu8 ", TTL: %" PRIu32 ".\n", node->nodeInfo.nodeId, node->ttlCnt);
|
|
if (node->ttlCnt < LINK_BROCK_THRESHOLD)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
DBG_WARNING("Lost Connection to NODE %" PRIu8 ".\n", node->nodeInfo.nodeId);
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Schedule next slot based on time allocate slice.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
*
|
|
* @return SUCCESS
|
|
* Other error code.
|
|
*
|
|
******************************************************************************/
|
|
static int32_t Linklayer_Routine(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
int32_t Status;
|
|
uint32_t tableIndx, entryIndx;
|
|
|
|
// Determine which routine entry is going to be performed.
|
|
tableIndx = L2_GetNextFrameNum(instPtr) % instPtr->rtneConfig.rtnePrd;
|
|
entryIndx = L2_GetNextSlotNum(instPtr);
|
|
L2_RTNE_TABLE_ENTRY rtneEntry = {0};
|
|
|
|
// Shift routine entry record.
|
|
instPtr->rtneConfig.last = instPtr->rtneConfig.curr;
|
|
instPtr->rtneConfig.curr = instPtr->rtneConfig.next;
|
|
instPtr->rtneConfig.next = &(instPtr->rtneConfig.rtneTable[tableIndx][entryIndx]);
|
|
rtneEntry = instPtr->rtneConfig.rtneTable[tableIndx][entryIndx];
|
|
DBG_INFO("## Routine: %" PRIu32 "-%" PRIu32 ", Routine period: %" PRIu32 ".\n", tableIndx, entryIndx,
|
|
instPtr->rtneConfig.rtnePrd);
|
|
|
|
switch (rtneEntry.slotType)
|
|
{
|
|
case L2_SLOT_IDLE:
|
|
// Skip a 2 ms slot.
|
|
DBG_INFO("Skipping idle slot (2 ms)...\n");
|
|
Status = SUCCESS;
|
|
break;
|
|
case L2_SLOT_ADVERTISE:
|
|
case L2_SLOT_ACKNOWLEDGE:
|
|
Status = L2_Scan_Routine(instPtr, &rtneEntry);
|
|
break;
|
|
case L2_SLOT_DISTRIBUTE:
|
|
case L2_SLOT_MANAGE:
|
|
case L2_SLOT_RTT:
|
|
case L2_SLOT_SERVICE:
|
|
Status = L2_Service_Routine(instPtr, &rtneEntry);
|
|
break;
|
|
default:
|
|
DBG_ERROR("UNKNOWN slot type [%" PRId8 "].\n", rtneEntry.slotType);
|
|
return EPARAM;
|
|
}
|
|
|
|
// check if routine is finished.
|
|
if (entryIndx >= L2_SLOTS_PER_FRAME - 1 && tableIndx >= instPtr->rtneConfig.rtnePrd - 1)
|
|
{
|
|
L2_EVENT rtneFinishEvent = {L2_ROUTINE_FINISH, &(instPtr->rtneConfig)};
|
|
AssertL2Event(instPtr, &rtneFinishEvent);
|
|
}
|
|
|
|
// Update TTL
|
|
uint32_t increment = 1;
|
|
L2_IterEditNode(instPtr->nodeList, &increment, IntcNodeTTL);
|
|
|
|
#ifdef DATALINK_ENABLE_AUTORECONNECT
|
|
if (L2_GetMainState(instPtr) != L2_INIT_STATE)
|
|
{
|
|
L2_IterDeleteNode(instPtr->nodeList, IsNodeConnected);
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_MEMBER && (L2_GetNodeById(instPtr->nodeList, instPtr->myInfo.headId) == NULL))
|
|
{
|
|
// reset scan process
|
|
L2_EVENT l2Event;
|
|
// Assert Net-Setup Done.
|
|
l2Event.event = L2_EV_LOST_CXN;
|
|
l2Event.msg = NULL;
|
|
AssertL2Event(instPtr, &l2Event);
|
|
}
|
|
}
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Execute a link layer fsm process.
|
|
*
|
|
* @param instPtr a pointer to physical layer controller instance
|
|
*
|
|
* @return SUCCESS
|
|
* Other error code.
|
|
*
|
|
******************************************************************************/
|
|
int32_t Linklayer_Proc(L2_INST *instPtr)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
int32_t Status;
|
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
|
TMC_INST *tmcRef = instPtr->config.tmcInstPtr;
|
|
|
|
if (instPtr->isEnable == false)
|
|
{
|
|
DBG_INFO("######## Link Layer is not Enabled ########\n");
|
|
return SUCCESS;
|
|
}
|
|
|
|
// FIXME: Consider time wrapping.
|
|
uint32_t nextTimeUnit = (TimeCtrl_GetIntCnt(tmcRef) + 1) / L2_SLOTS_PER_FRAME;
|
|
if (nextTimeUnit < instPtr->netStartTime)
|
|
{
|
|
DBG_WARNING("Linklayer not start yet, next time unit: %" PRIu32 ", start time unit: %" PRIu32 ".\n",
|
|
nextTimeUnit, instPtr->netStartTime);
|
|
return EIGNORE;
|
|
}
|
|
|
|
// Update slot number.
|
|
L2_UpdateSlotNum(instPtr);
|
|
|
|
DBG_INFO("######## Current frameNum: %" PRIu32 ", SlotNum: %" PRIu32 " ########\n",
|
|
instPtr->frameNum.curr, instPtr->slotNum.curr);
|
|
|
|
// Sync System info
|
|
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
|
|
|
// Update frame status.
|
|
L2_FrameStateUpdate(instPtr);
|
|
|
|
// Handle frame received in last slot.
|
|
if (L2_isDataAvail(instPtr) == true)
|
|
{
|
|
if (Linklayer_PktHandler(instPtr) != SUCCESS)
|
|
{
|
|
DBG_ERROR("Failed to handle last received frame: %" PRId8 ".\n", L2_GetLastFrameType(instPtr));
|
|
}
|
|
}
|
|
|
|
// Run Link layer routine, setup next slot procedure.
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
|
{
|
|
Phy_SetMode(phyRef, PHY_MODE_POLL);
|
|
Status = Linklayer_Routine(instPtr);
|
|
}
|
|
else
|
|
{ // L2_NODE_MEMBER
|
|
if (L2_isCxn2Net(instPtr))
|
|
{
|
|
Phy_SetMode(phyRef, PHY_MODE_POLL);
|
|
Status = Linklayer_Routine(instPtr);
|
|
}
|
|
else
|
|
{
|
|
Phy_SetMode(phyRef, PHY_MODE_LISTEN);
|
|
Status = L2_Scan_Proc(instPtr);
|
|
}
|
|
}
|
|
|
|
// Check if previous runs has error occurred.
|
|
if (Status != SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
// Check and execute scheduled event.
|
|
L2_EventPoolHandler(instPtr);
|
|
|
|
// Update link layer state.
|
|
instPtr->mainState = instPtr->nextState;
|
|
instPtr->linkLog.tuNum = instPtr->frameNum.curr;
|
|
instPtr->linkLog.slotNum = (uint8_t)instPtr->slotNum.curr;
|
|
instPtr->linkLog.nodeType = (L2_GetNodeType(instPtr) == L2_NODE_HEAD) ? 0xAA : 0xCC;
|
|
instPtr->linkLog.cxnStatus = (L2_isCxn2Net(instPtr)) ? 0x11 : 0x00;
|
|
instPtr->linkLog.linkStage = (instPtr->mainState == L2_INIT_STATE) ? 0x11 : 0x22;
|
|
instPtr->linkLog.recxnCnt = instPtr->log.reconnectCnt;
|
|
instPtr->linkLog.antIndex = instPtr->config.phyInstPtr->antIndex.curr;
|
|
instPtr->linkLog.advTxCnt = (uint16_t)instPtr->log.advTxCnt;
|
|
instPtr->linkLog.advRecvCnt = (uint16_t)instPtr->log.advRecvCnt;
|
|
instPtr->linkLog.advCorrectCnt = (uint16_t)instPtr->log.advCorrectCnt;
|
|
instPtr->linkLog.ackTxCnt = instPtr->log.ackTxCnt;
|
|
instPtr->linkLog.ackRecvCnt = instPtr->log.ackRecvCnt;
|
|
instPtr->linkLog.ackCorrectCnt = instPtr->log.ackCorrectCnt;
|
|
instPtr->linkLog.disTxCnt = instPtr->log.disTxCnt;
|
|
instPtr->linkLog.disRecvCnt = instPtr->log.disRecvCnt;
|
|
instPtr->linkLog.disCorrectCnt = instPtr->log.disCorrectCnt;
|
|
instPtr->linkLog.mngTxCnt = instPtr->log.mngTxCnt;
|
|
instPtr->linkLog.mngRecvCnt = instPtr->log.mngRecvCnt;
|
|
instPtr->linkLog.mngCorrectCnt = instPtr->log.mngCorrectCnt;
|
|
instPtr->linkLog.rttTxCnt = instPtr->log.rttTxCnt;
|
|
instPtr->linkLog.rttRecvCnt = instPtr->log.rttRecvCnt;
|
|
instPtr->linkLog.rttCorrectCnt = instPtr->log.rttCorrectCnt;
|
|
instPtr->linkLog.svcTxCnt = instPtr->log.svcTxCnt;
|
|
instPtr->linkLog.svcRecvCnt = instPtr->log.svcRecvCnt;
|
|
instPtr->linkLog.svcCorrectCnt = instPtr->log.svcCorrectCnt;
|
|
instPtr->linkLog.timeDev = (instPtr->log.timeDev > INT32_MAX)
|
|
? INT32_MAX : ((instPtr->log.timeDev < INT32_MIN) ? INT32_MIN : (int32_t)instPtr->log.timeDev);
|
|
instPtr->linkLog.sendId = instPtr->log.txLog.dataId;
|
|
instPtr->linkLog.recvId = instPtr->log.rxLog.dataId;
|
|
|
|
SysMonitor_UpdateLinklayerLog(&(instPtr->linkLog));
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Layer 2 setup next slot operation, update current operating frame.
|
|
*
|
|
* @param instPtr a pointer to linklayer instance
|
|
* @param txrxMode tx/rx state for next slot
|
|
* @param frameType frame type of next slot.
|
|
*
|
|
* @return SUCCESS/FAILURE
|
|
*
|
|
******************************************************************************/
|
|
int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE frameType)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
|
int32_t Status;
|
|
if (frameType < L2_FRAME_ADV || frameType > L2_FRAME_SVC)
|
|
{
|
|
DBG_WARNING("L2_SetupNextSlot(): UNKNOWN L2-FrameType %" PRId8 "\n", frameType);
|
|
return FAILURE;
|
|
}
|
|
|
|
// logging
|
|
if (txrxMode == L2_TOR_TX)
|
|
{
|
|
instPtr->log.frameTx++;
|
|
switch (frameType)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
instPtr->log.advTxCnt++;
|
|
break;
|
|
case L2_FRAME_ACK:
|
|
instPtr->log.ackTxCnt++;
|
|
break;
|
|
case L2_FRAME_DIS:
|
|
instPtr->log.disTxCnt++;
|
|
break;
|
|
case L2_FRAME_MNG:
|
|
instPtr->log.mngTxCnt++;
|
|
break;
|
|
case L2_FRAME_RTT:
|
|
instPtr->log.rttTxCnt++;
|
|
break;
|
|
case L2_FRAME_SVC:
|
|
instPtr->log.svcTxCnt++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (txrxMode == L2_TOR_RX)
|
|
{
|
|
instPtr->log.frameRx++;
|
|
switch (frameType)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
instPtr->log.advRxCnt++;
|
|
break;
|
|
case L2_FRAME_ACK:
|
|
instPtr->log.ackRxCnt++;
|
|
break;
|
|
case L2_FRAME_DIS:
|
|
instPtr->log.disRxCnt++;
|
|
break;
|
|
case L2_FRAME_MNG:
|
|
instPtr->log.mngRxCnt++;
|
|
break;
|
|
case L2_FRAME_RTT:
|
|
instPtr->log.rttRxCnt++;
|
|
break;
|
|
case L2_FRAME_SVC:
|
|
instPtr->log.svcRxCnt++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if _DEBUG_LEVEL >= 3
|
|
char *torStr = NULL;
|
|
char *frameStr = NULL;
|
|
switch (txrxMode)
|
|
{
|
|
case L2_TOR_SUSPEND:
|
|
torStr = "SUSPEND";
|
|
break;
|
|
case L2_TOR_TX:
|
|
torStr = "TX";
|
|
break;
|
|
case L2_TOR_RX:
|
|
torStr = "RX";
|
|
break;
|
|
}
|
|
switch (frameType)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
frameStr = "Advertisement";
|
|
break;
|
|
case L2_FRAME_ACK:
|
|
frameStr = "Acknowledgement";
|
|
break;
|
|
case L2_FRAME_DIS:
|
|
frameStr = "Distribution";
|
|
break;
|
|
case L2_FRAME_MNG:
|
|
frameStr = "Management";
|
|
break;
|
|
case L2_FRAME_RTT:
|
|
frameStr = "Round Trip Time";
|
|
break;
|
|
case L2_FRAME_SVC:
|
|
frameStr = "Service";
|
|
break;
|
|
default:
|
|
frameStr = "UNKNOWN Frame";
|
|
break;
|
|
}
|
|
DBG_INFO("# Setup Next Slot # [%" PRIu32 "-%" PRIu32 "], %s, %s.\n",
|
|
instPtr->frameNum.next,
|
|
instPtr->slotNum.next,
|
|
torStr, frameStr);
|
|
#endif
|
|
|
|
// Update frame and tx/rx mode record.
|
|
// Frame types shift (last <- curr <- next)
|
|
L2_RcdShift(&(instPtr->frame), frameType);
|
|
L2_RcdShift(&(instPtr->tor), txrxMode);
|
|
|
|
TIME_WORD pollTime = {0, 0};
|
|
pollTime.int_part = TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr) + 1;
|
|
Status = Phy_SetTimeWord(phyRef, &pollTime, PHY_TIME_WORD_POLL);
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("Physical set poll time failed, with error code: %" PRId32 "\n", Status);
|
|
}
|
|
|
|
PHY_TOR_TYPE tor;
|
|
switch (txrxMode)
|
|
{
|
|
case L2_TOR_SUSPEND:
|
|
tor = PHY_TOR_SUSPEND;
|
|
break;
|
|
case L2_TOR_TX:
|
|
tor = PHY_TOR_TX;
|
|
break;
|
|
case L2_TOR_RX:
|
|
tor = PHY_TOR_RX;
|
|
break;
|
|
default:
|
|
DBG_ERROR("Invalid txrx mode :%" PRId8 ".\n", txrxMode);
|
|
return EPARAM;
|
|
}
|
|
|
|
Status = Phy_SetupNextSlot(phyRef, tor, L2_L2frame2L1frame(frameType,
|
|
instPtr->config.serviceRate), instPtr->sendPktData);
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("Physical setup failed, with error code: %" PRId32 "\n", Status);
|
|
}
|
|
return Status;
|
|
}
|
|
/** @} LinkLayer_Main*/
|
|
/** @} LinkLayer*/
|