Files
datalink_nc_mode/datalink814_ge/src/linklayer/linklayer814.c
T

1409 lines
42 KiB
C

/*****************************************************************************/
/**
* Description: A brief description of this file
*
* Date: 2021-11-13 13:32
* LastEditors: Fan Hao
* LastEditTime: 2021-11-23 10:57
* Revisions: Rev 0.0
* History:
* [2021-11-23]: Initial version.
* [2022-03-28]: Add bre test mode.
*
* Copyright(c) 2021 Beijing Institute of Technology.
* Lab of Communication and Networking
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <stdlib.h>
#include <string.h>
#include "linklayer814.h"
#include "linklayer814_types.h"
#include "msg_def.h"
#include "../error.h"
#include "../phy_ctrl/phy_ctrlreg.h"
#include "../time_ctrl/time_ctrl.h"
#include "../util/util.h"
#include "../common.h"
/************************** Constant Definitions *****************************/
#define NET_START_TIME_INFTY UINT32_MAX
/************************** Variable Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Function Prototypes ******************************/
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_EventPoolHandler(L2_INST* instPtr);
static inline void UpdateMainSate(L2_INST* instPtr, L2_NODE_STATE newSate) {
ASSERT(instPtr != NULL);
DBG_INFO("MainStateUpdate: %d -> %d\n", instPtr->mainState, newSate);
instPtr->nextState = newSate;
}
static void L2_SetSlotNum(L2_INST* instPtr, uint32_t newSlotNum){
ASSERT(instPtr != NULL);
DBG_INFO("Set new slot number to %u\n", newSlotNum);
instPtr->slotNum.next = newSlotNum;
}
static void L2_SetFrameNum(L2_INST* instPtr, uint32_t newFrameNum){
ASSERT(instPtr != NULL);
DBG_INFO("Set new frame number to %u\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 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_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 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;
}
// TODO: Multi-node RTT
/**
* @brief Get the RTT FSM.
*/
inline L2_RTT_FSM* L2_GetRttFsm(L2_INST* instPtr){
ASSERT(instPtr != NULL);
return instPtr->rttFSM;
}
/*****************************************************************************/
/**
* @brief Creat a new schedule envent, register event in schedule event pool.
*
* @param instPtr a pointer to linklayer instance
* @param event event type of the new schedule event.
*
* @return NULL error occurred
* Pointer to schedule event.
*
******************************************************************************/
L2_SCHD_EVENT* L2_CreatNewSchdEvent(L2_INST* instPtr, L2_EVENT_TYPE event){
L2_SCHD_EVENT* schdEventPtr = NULL;
if(instPtr->schdEventCnt >= L2_SCHD_EVENT_MAX){
DBG_ERROR("Schedule event number exceeds the max, no more schedule event can be created.\n");
return NULL;
}
schdEventPtr = (L2_SCHD_EVENT*)malloc(sizeof(L2_SCHD_EVENT));
if(schdEventPtr == NULL){
free(schdEventPtr);
return NULL;
}
if(event < L2_EV_SCAN_PROC_DONE || event > L2_ROUTINE_UPDATE){
DBG_ERROR("Unknown event type: %d.\n", event);
return NULL;
}
schdEventPtr->eventId = instPtr->schdEventCnt;
schdEventPtr->l2Event.msg = NULL;
schdEventPtr->isSchd = false;
schdEventPtr->schdSlot = L2_SLOTNO_NONE;
schdEventPtr->schdFrame = L2_FRAMENO_NONE;
instPtr->l2SchdEventPool[instPtr->schdEventCnt] = schdEventPtr;
instPtr->schdEventCnt++;
return schdEventPtr;
}
/*****************************************************************************/
/**
* @brief Delete a schedule event, remove the event from event pool,
* release memory, release event ID.
*
* @param instPtr a pointer to linklayer instance
* @param eventId ID of the event
*
* @return SUCCESS
* error code
*
******************************************************************************/
int32_t L2_DeletSchdEvent(L2_INST* instPtr, int32_t eventId){
ASSERT(instPtr != NULL);
if (eventId > instPtr->schdEventCnt) {
return EIGNORE;
}
L2_SCHD_EVENT* schdEvent = instPtr->l2SchdEventPool[eventId];
for(int32_t i = schdEvent->eventId; i < instPtr->schdEventCnt; i++){
if(i == instPtr->schdEventCnt - 1){
instPtr->l2SchdEventPool[i] = NULL;
}
else{
instPtr->l2SchdEventPool[i] = instPtr->l2SchdEventPool[i+1];
}
}
instPtr->schdEventCnt --;
if(schdEvent->l2Event.msg != NULL) {
free(schdEvent->l2Event.msg);
}
free(schdEvent);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Clear all event in the event pool.
*
* @param instPtr a pointer to linklayer instance
*
* @return NONE
*
******************************************************************************/
void L2_ClearSchdEvent(L2_INST* instPtr){
ASSERT(instPtr != NULL);
for(int32_t i = 0; i < instPtr->schdEventCnt; i++){
if(instPtr->l2SchdEventPool[i]->l2Event.msg != NULL) {
free(instPtr->l2SchdEventPool[i]->l2Event.msg);
}
free(instPtr->l2SchdEventPool[i]);
}
instPtr->schdEventCnt = 0;
}
/*****************************************************************************/
/**
* @brief Append extra message content to specific schedule event.
*
* @param schdEvent pointer to the schedule event.
* msg pointer to the append content.
*
* @return SUCCESS.
* error code.
*
******************************************************************************/
inline int32_t L2_SchdEventAppendMsg(L2_SCHD_EVENT* schdEvent, void* msg){
ASSERT(schdEvent != NULL);
schdEvent->l2Event.msg = msg;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Cancel a scheduled event.
*
* @param schdEvent pointer to the schedule event.
*
* @return SUCCESS.
*
******************************************************************************/
int32_t L2_CancelEvent(L2_SCHD_EVENT* schdEvent){
ASSERT(schdEvent != NULL);
if(schdEvent->isSchd == false){
DBG_WARNING("Event %d has not been scheduled yet.\n", schdEvent->eventId);
}
schdEvent->isSchd = false;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Check if the event was scheduled.
*
* @param schdEvent pointer to the schedule event.
*
* @return true.
* false.
*
******************************************************************************/
inline bool L2_isEventScheduled(L2_SCHD_EVENT* schdEvent){
ASSERT(schdEvent != NULL);
return schdEvent->isSchd;
}
/*****************************************************************************/
/**
* @brief Schedule a event at a specific time(indexed by frame and slot number)
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param frameNum schedule frame number
* @param slotNum schedule slot number
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_ScheduleEventAt(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t frameNum, uint32_t slotNum){
ASSERT(schdEvent != NULL);
if(L2_isEventScheduled(schdEvent) == true){
DBG_ERROR("Event %d has already been scheduled.\n", schdEvent->eventId);
return FAILURE;
}
if(frameNum <= L2_GetCurrentFrameNum(instPtr) && slotNum < L2_GetCurrentSlotNum(instPtr)){
DBG_ERROR("Cannot schedule event %d to the past(current: [%u-%u], schedule: [%u-%u]).\n",
schdEvent->eventId, L2_GetCurrentFrameNum(instPtr), L2_GetCurrentSlotNum(instPtr), frameNum, slotNum);
return FAILURE;
}
schdEvent->isSchd = true;
schdEvent->schdFrame = frameNum;
schdEvent->schdSlot = slotNum;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Schedule a event after a specific time period.
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param numSlots how many slot later the event should be scheduled
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_ScheduleEventAfter(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t numSlots){
ASSERT(schdEvent != NULL);
if(L2_isEventScheduled(schdEvent) == true){
DBG_ERROR("Event %d has already been scheduled.\n", schdEvent->eventId);
return FAILURE;
}
uint32_t frameNum = L2_GetCurrentFrameNum(instPtr) + (numSlots/L2_SLOTS_PER_FRAME);
uint32_t slotNum = L2_GetCurrentSlotNum(instPtr) + (numSlots%L2_SLOTS_PER_FRAME);
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
}
/*****************************************************************************/
/**
* @brief Reschedule a event at a specific time(indexed by frame and slot number)
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param frameNum schedule frame number
* @param slotNum schedule slot number
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_RecheduleEventAt(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t frameNum, uint32_t slotNum){
ASSERT(schdEvent != NULL);
if(schdEvent->isSchd == false){
DBG_WARNING("Event %d has not been scheduled yet.\n", schdEvent->eventId);
}
schdEvent->isSchd = false;
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
}
/*****************************************************************************/
/**
* @brief Rechedule a event after a specific time period.
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param numSlots how many slot later the event should be scheduled
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_RecheduleEventAfter(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t numSlots){
ASSERT(schdEvent != NULL);
if(schdEvent->isSchd == false){
DBG_WARNING("Event %d has not been scheduled yet.\n", schdEvent->eventId);
}
return L2_ScheduleEventAfter(instPtr, schdEvent, numSlots);
}
/*****************************************************************************/
/**
* @brief Check and excute schedule event in event pool illiterate.
*
* @param instPtr a pointer to linklayer instance
*
* @return NONE.
*
******************************************************************************/
static void L2_EventPoolHandler(L2_INST* instPtr){
ASSERT(instPtr != NULL);
for(int32_t i = 0; i < instPtr->schdEventCnt; i++){
if(instPtr->l2SchdEventPool[i]->isSchd == true){
if(instPtr->l2SchdEventPool[i]->schdFrame == instPtr->frameNum.curr
&& instPtr->l2SchdEventPool[i]->schdSlot == instPtr->slotNum.curr){
AssertL2Event(instPtr, &(instPtr->l2SchdEventPool[i]->l2Event));
}
}
}
}
/*****************************************************************************/
/**
* @brief Shift L2 status record.(newval->next->curr->last)
*
* @param instPtr A pointer to physical layer control instance.
*
* @return NONE.
*
******************************************************************************/
inline void L2_RcdShift(L2_RCD* rcd, int32_t netxVal) {
ASSERT(rcd != NULL);
rcd->last = rcd->curr;
rcd->curr = rcd->next;
rcd->next = netxVal;
}
/*****************************************************************************/
/**
* @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.
*
******************************************************************************/
// FIXME: Only for test
int w2AcqRecvCnt = 0;
int w2AcqRecvSuccessCnt = 0;
int mgmtRecvCnt = 0;
int mgmtRecvSuccessCnt = 0;
int tsyncRecvCnt = 0;
int tsyncRecvSuccessCnt = 0;
int svcRecvCnt = 0;
int svcRecvSuccessCnt = 0;
int recvCnt = 0;
int frameLen = 0;
void L2_FrameStateUpdate(L2_INST* instPtr) {
ASSERT(instPtr != NULL);
PHY_INST* phyRef = instPtr->config.phyInstPtr;
// Update physical layer status.
// Phy_UpdateState(phyRef);
// Frame types shift (last <- curr <- next)
L2_RcdShift(&(instPtr->frame), L2_NONE_FRAME);
L2_RcdShift(&(instPtr->tor), L2_TOR_SUSPEND);
// Update frame state.
if (Phy_IsFrameValid(phyRef) == false) {
L2_DataAvailUpdate(instPtr, false);
return;
}
DBG_INFO("A frame received, checking data validation...\n");
DBG_INFO("Last frame type is: %u.\n", instPtr->frame.last);
Phy_RetrieveRecvData(phyRef, instPtr->recvPktData);
switch (instPtr->frame.last) {
case L2_INTRA_SCAN_FRAME:
// INTRA_BM_FRAME could be received if current frame type is INTRA_BM_FRAME
case L2_INTRA_BM_FRAME:
if (L2_CrcCheck(instPtr->recvPktData, BM_MSG_CRC_OFFSET / 8,
BM_MSG_CRC_OFFSET / 8, L2_CRC8_31) == true) {
L2_DataAvailUpdate(instPtr, true);
}
else {
L2_DataAvailUpdate(instPtr, false);
}
break;
case L2_INTRA_W2_ACQ_FRAME:
// FIXME: Only for test
w2AcqRecvCnt++;
if (L2_CrcCheck(instPtr->recvPktData,
W2ACQ_FRAME_CRC_DLEN, W2ACQ_FRAME_CRC_POS,
L2_CRC16_8005) == true) {
L2_DataAvailUpdate(instPtr, true);
// FIXME: Only for test
w2AcqRecvSuccessCnt++;
}
else {
L2_DataAvailUpdate(instPtr, false);
}
break;
case L2_INTRA_MGMT_FRAME:
// FIXME: Only for test
mgmtRecvCnt++;
recvCnt ++ ;
L2_DataAvailUpdate(instPtr, true);
// FIXME: Only for test
mgmtRecvSuccessCnt ++;
break;
case L2_INTRA_TSYNC_FRAME:
// FIXME: Only for test
tsyncRecvCnt++;
recvCnt ++ ;
L2_DataAvailUpdate(instPtr, true);
// FIXME: Only for test
tsyncRecvSuccessCnt ++;
break;
case L2_INTRA_SVC_FRAME:
// FIXME: Only for test
svcRecvCnt++;
recvCnt ++ ;
if (L2_CrcCheck(instPtr->recvPktData,
PDUH0_HEADER_CRC_OFFSET/8, PDUH0_HEADER_CRC_OFFSET/8,
L2_CRC8_31) == true) {
L2_DataAvailUpdate(instPtr, true);
// FIXME: Only for test
svcRecvSuccessCnt++;
}
else {
L2_DataAvailUpdate(instPtr, false);
}
break;
default:
L2_DataAvailUpdate(instPtr, false);
break;
}
}
/*****************************************************************************/
/**
* @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 Corresponding frame length
* L2_FRAME_NONE_LEN if the frame type code cannot be recognized.
*
******************************************************************************/
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 = SUCCESS;
if (frameType < L2_INTER_SCAN_FRAME || frameType > L2_INTRA_SVC_FRAME) {
return FAILURE;
}
#if _814_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_INTER_SCAN_FRAME:
frameStr = "intER Scan";
break;
case L2_INTRA_SCAN_FRAME:
frameStr = "intRA Scan";
break;
case L2_INTER_BM_FRAME:
frameStr = "intER BM";
break;
case L2_INTRA_BM_FRAME:
frameStr = "intRA BM";
break;
case L2_INTER_W2_ACQ_FRAME:
frameStr = "intER W2Acq";
break;
case L2_INTRA_W2_ACQ_FRAME:
frameStr = "intRA W2Acq";
break;
case L2_INTER_MGMT_FRAME:
frameStr = "intER Mgmt";
break;
case L2_INTRA_MGMT_FRAME:
frameStr = "intRA Mgmt";
break;
case L2_INTER_TSYNC_FRAME:
frameStr = "intER TSync";
break;
case L2_INTRA_TSYNC_FRAME:
frameStr = "intRA TSync";
break;
case L2_INTER_SVC_FRAME:
frameStr = "intER Svc";
break;
case L2_INTRA_SVC_FRAME:
frameStr = "intRA Svc";
break;
default:
break;
}
DBG_INFO("# Setup Next Slot # [%u-%u], %s, %s.\n",
instPtr->frameNum.next,
instPtr->slotNum.next,
torStr, frameStr);
#endif
// Update frame and tx/rx mode record.
instPtr->frame.next = frameType;
instPtr->tor.next = txrxMode;
TIME_WORD pullTime = {0, 0};
pullTime.int_part = TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr) + 1;
Status = Phy_SetTimeWord(phyRef, &pullTime, TIME_WORD_POLL);
if(Status != SUCCESS){
DBG_ERROR("Physical set pull time failed, with error code: %d\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 :%d.\n", txrxMode);
return EPARAM;
}
Status = Phy_SetupNextSlot(phyRef, tor, L2_L2frame2L1frame(frameType), instPtr->sendPktData);
if(Status != SUCCESS){
DBG_ERROR("Physical setup failed, with error code: %d\n", Status);
}
return Status;
}
/*****************************************************************************/
/**
* @brief Get corresponding frame length in byte of L2 frame.
*
* @param l2FrameType
*
* @return Corresponding frame length
* L2_FRAME_NONE_LEN if the frame type code cannot be recognized.
*
******************************************************************************/
uint32_t L2_GetFrameLen(L2_FRAME_TYPE l2FrameType) {
return Phy_GetFrameLen(L2_L2frame2L1frame(l2FrameType));
}
/*****************************************************************************/
/**
* @brief Convert L2 frame type to L1 frame type
*
* @param phyInstPtr A pointer to physical layer control instance.
*
* @return L1 frame type.
*
******************************************************************************/
#ifdef TEST_200KBPS
L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame) {
switch (l2Frame) {
case L2_INTER_SCAN_FRAME:
return L1_2KBPS_20MS_FRAME;
case L2_INTRA_SCAN_FRAME:
return L1_10KBPS_10MS_FRAME;
case L2_INTER_BM_FRAME:
return L1_2KBPS_100MS_FRAME;
case L2_INTRA_BM_FRAME:
return L1_10KBPS_20MS_FRAME;
case L2_INTER_W2_ACQ_FRAME:
return L1_40KBPS_10MS_FRAME;
case L2_INTRA_W2_ACQ_FRAME:
return L1_200KBPS_5MS_FRAME;
case L2_INTER_MGMT_FRAME:
return L1_40KBPS_20MS_FRAME;
case L2_INTRA_MGMT_FRAME:
return L1_200KBPS_5MS_FRAME;
case L2_INTER_TSYNC_FRAME:
return L1_40KBPS_20MS_FRAME;
case L2_INTRA_TSYNC_FRAME:
return L1_200KBPS_5MS_FRAME;
case L2_INTER_SVC_FRAME:
return L1_40KBPS_20MS_FRAME;
case L2_INTRA_SVC_FRAME:
return L1_200KBPS_5MS_FRAME;
default:
return L1_NONE_FRAME;
}
}
// FIXME: Only for test 1.2Mbps Frame
#else
L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame) {
switch (l2Frame) {
case L2_INTER_SCAN_FRAME:
return L1_2KBPS_20MS_FRAME;
case L2_INTRA_SCAN_FRAME:
return L1_10KBPS_10MS_FRAME;
case L2_INTER_BM_FRAME:
return L1_2KBPS_100MS_FRAME;
case L2_INTRA_BM_FRAME:
return L1_10KBPS_20MS_FRAME;
case L2_INTER_W2_ACQ_FRAME:
return L1_40KBPS_10MS_FRAME;
case L2_INTRA_W2_ACQ_FRAME:
return L1_200KBPS_5MS_FRAME;
case L2_INTER_MGMT_FRAME:
return L1_40KBPS_20MS_FRAME;
case L2_INTRA_MGMT_FRAME:
return L1_1M2BPS_5MS_FRAME;
case L2_INTER_TSYNC_FRAME:
return L1_40KBPS_20MS_FRAME;
case L2_INTRA_TSYNC_FRAME:
return L1_1M2BPS_5MS_FRAME;
case L2_INTER_SVC_FRAME:
return L1_40KBPS_20MS_FRAME;
case L2_INTRA_SVC_FRAME:
return L1_1M2BPS_5MS_FRAME;
default:
return L1_NONE_FRAME;
}
}
#endif
/*****************************************************************************/
/**
* @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
*
* @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_INST failed.\n");
return EALLOC;
}
memset(*instPtr, 0x00, sizeof(L2_INST));
memcpy(&((*instPtr)->config), config, sizeof(L2_CONFIG));
// Packet buffer
(*instPtr)->sendPktData = calloc(L2_PACKET_LEN_MAX/sizeof(uint64_t), sizeof(uint64_t));
if((*instPtr)->sendPktData == NULL) {
DBG_ERROR("Allocate memory for sendPktData failed.\n");
Status = EALLOC;
goto error;
}
(*instPtr)->recvPktData = calloc(L2_PACKET_LEN_MAX/sizeof(uint64_t), sizeof(uint64_t));
if((*instPtr)->recvPktData == NULL) {
DBG_ERROR("Allocate memory for recvPktData failed.\n");
Status = EALLOC;
goto error;
}
// Mpc buff Init
(*instPtr)->mgmtMsgRecvBuff0 = calloc(MSG_STROAGE_BUFF_MAX/sizeof(uint64_t), sizeof(uint64_t));
if((*instPtr)->mgmtMsgRecvBuff0 == NULL) {
DBG_ERROR("Allocate memory for mgmtMsgRecvBuff0 failed.\n");
Status = EALLOC;
goto error;
}
(*instPtr)->svcMsgRecvBuff0 = calloc(MSG_STROAGE_BUFF_MAX/sizeof(uint64_t), sizeof(uint64_t));
if((*instPtr)->svcMsgRecvBuff0 == NULL) {
DBG_ERROR("Allocate memory for svcMsgRecvBuff0 failed.\n");
Status = EALLOC;
goto error;
}
(*instPtr)->mgmtMsgRecvBuff1 = calloc(MSG_STROAGE_BUFF_MAX/sizeof(uint64_t), sizeof(uint64_t));
if((*instPtr)->mgmtMsgRecvBuff1 == NULL) {
DBG_ERROR("Allocate memory for mgmtMsgRecvBuff1 failed.\n");
Status = EALLOC;
goto error;
}
(*instPtr)->svcMsgRecvBuff1 = calloc(MSG_STROAGE_BUFF_MAX/sizeof(uint64_t), sizeof(uint64_t));
if((*instPtr)->svcMsgRecvBuff1 == NULL) {
DBG_ERROR("Allocate memory for svcMsgRecvBuff1 failed.\n");
Status = EALLOC;
goto error;
}
// Reset basic info
(*instPtr)->netStartTime = UINT32_MAX;
(*instPtr)->schdEventCnt = 0;
(*instPtr)->rtneConfig.last = NULL;
(*instPtr)->rtneConfig.curr = NULL;
(*instPtr)->rtneConfig.next = NULL;
(*instPtr)->isEnable = false;
(*instPtr)->cxn2Net = false;
(*instPtr)->dataAvail = false;
(*instPtr)->frame.last = L2_NONE_FRAME;
(*instPtr)->frame.curr = L2_NONE_FRAME;
(*instPtr)->frame.next = L2_NONE_FRAME;
(*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 = INIT_STATE;
(*instPtr)->nextState = INIT_STATE;
(*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)->myInfo.nodeType = config->myType;
(*instPtr)->myInfo.nodeId = config->myId;
(*instPtr)->myInfo.clustId = config->clustId;
(*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 buffer count
(*instPtr)->mgmtMsgRecvCnt0 = 0;
(*instPtr)->mgmtMsgRecvCnt1 = 0;
(*instPtr)->svcMsgRecvCnt0 = 0;
(*instPtr)->svcMsgRecvCnt1 = 0;
(*instPtr)->buffSwitch = 0;
NodeList_Init(&((*instPtr)->nodeList));
Status = ScanNet_Init(&((*instPtr)->scanNetFSM));
if (Status != SUCCESS) {
DBG_ERROR("ScanNet_Init runs failed, with error code: %d.\n", Status);
goto error;
}
Status = MgmtNet_Init(&((*instPtr)->mgmtNetFSM));
if (Status != SUCCESS) {
DBG_ERROR("MgmtNet_Init runs failed, with error code: %d.\n", Status);
goto error;
}
Status = ServiceNet_Init(&((*instPtr)->serviceNetFSM));
if (Status != SUCCESS) {
DBG_ERROR("ServiceNet_Init runs failed, with error code: %d.\n", Status);
goto error;
}
Status = RTT_Init(&((*instPtr)->rttFSM));
if (Status != SUCCESS) {
DBG_ERROR("RTT_Init runs failed, with error code: %d.\n", Status);
goto error;
}
return SUCCESS;
error:
Linklayer_Destroy(*instPtr);
return Status;
}
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
instPtr->netStartTime = UINT32_MAX;
instPtr->schdEventCnt = 0;
instPtr->rtneConfig.last = NULL;
instPtr->rtneConfig.curr = NULL;
instPtr->rtneConfig.next = NULL;
instPtr->cxn2Net = false;
instPtr->dataAvail = false;
instPtr->frame.last = L2_NONE_FRAME;
instPtr->frame.curr = L2_NONE_FRAME;
instPtr->frame.next = L2_NONE_FRAME;
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 = INIT_STATE;
instPtr->nextState = INIT_STATE;
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->myInfo.nodeType = config->myType;
instPtr->myInfo.nodeId = config->myId;
instPtr->myInfo.clustId = config->clustId;
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 buffer count
instPtr->mgmtMsgRecvCnt0 = 0;
instPtr->mgmtMsgRecvCnt1 = 0;
instPtr->svcMsgRecvCnt0 = 0;
instPtr->svcMsgRecvCnt1 = 0;
instPtr->buffSwitch = 0;
// Reset according instance
L2_ClearSchdEvent(instPtr);
NodeList_Clear(instPtr->nodeList);
ScanNet_Reset(instPtr->scanNetFSM);
MgmtNet_Reset(instPtr->mgmtNetFSM);
ServiceNet_Reset(instPtr->serviceNetFSM);
RTT_Reset(instPtr->rttFSM);
return SUCCESS;
}
void Linklayer_Destroy(L2_INST* instPtr){
ASSERT(instPtr != NULL);
free(instPtr->sendPktData);
free(instPtr->recvPktData);
free(instPtr->mgmtMsgRecvBuff0);
free(instPtr->svcMsgRecvBuff0);
free(instPtr->mgmtMsgRecvBuff1);
free(instPtr->svcMsgRecvBuff1);
// Destroy FSMs and nodeList
NodeList_Destroy(instPtr->nodeList);
ScanNet_Destroy(instPtr->scanNetFSM);
MgmtNet_Destroy(instPtr->mgmtNetFSM);
ServiceNet_Destroy(instPtr->serviceNetFSM);
RTT_Destroy(instPtr->rttFSM);
free(instPtr);
}
int32_t Linklayer_Start(L2_INST* instPtr){
ASSERT(instPtr != NULL);
instPtr->netStartTime = TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr)/L2_SLOTS_PER_FRAME + 1;
instPtr->isEnable = true;
return SUCCESS;
}
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");
//TODO: Clear ACK
break;
}
case L2_EV_MGMT_PROC_DONE: {
DBG_INFO("Event L2_EV_MGMT_PROC_DONE asserted....\n");
break;
}
case L2_EV_NET_SETUP_DONE: {
DBG_INFO("Event L2_EV_NETSETUP_DONE asserted....\n");
if(instPtr->myInfo.nodeType != HEAD_NODE){
instPtr->cxn2Net = true;
}
else{ // Head node
UpdateMainSate(instPtr, NORMAL_STATE);
}
break;
}
case L2_EV_TIME_SYNC: {
DBG_INFO("Event L2_EV_TIME_SYNC asserted....\n");
break;
}
case L2_EV_LINK_SET_REQ: {
DBG_INFO("Event L2_EV_LINK_SET_REQ asserted....\n");
break;
}
case L2_EV_LOST_CXN: {
DBG_INFO("Event L2_EV_LOST_CXN asserted....\n");
DBG_WARNING("Lost connection with head node [%d].\n", instPtr->config.headId);
instPtr->cxn2Net = false;
break;
}
case L2_EV_LOST_NODE: {
DBG_INFO("Event L2_EV_LOST_NODE asserted....\n");
break;
}
case L2_ROUTINE_FINISH: {
DBG_INFO("Event L2_ROUTINE_FINISH asserted....\n");
if(instPtr->nextState == INIT_STATE){
// Reset scan net FMS for next scan process.
ScanNet_Reset(instPtr->scanNetFSM);
UpdateMainSate(instPtr, NORMAL_STATE);
instPtr->rtneConfig.rtneTable = normalTable;
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable);
}
else if(instPtr->nextState == NORMAL_STATE){
instPtr->rtneConfig.rtneTable = normalTable;
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable);
}
else if(instPtr->nextState == SEEK_STATE){
instPtr->rtneConfig.rtneTable = seekTable;
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(seekTable);
}
else if(instPtr->nextState == INTRA_SEEK_STATE){
instPtr->rtneConfig.rtneTable = intraSeekTable;
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(intraSeekTable);
}
else if(instPtr->nextState == INTER_SEEK_STATE){
instPtr->rtneConfig.rtneTable = interSeekTable;
instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(interSeekTable);
}
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 %d asserted.\n", l2Event->event);
break;
}
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Handle l2 packet correctly received.
*
* @param instPtr a pointer to physical layer controller instance
* @param frameType
*
* @return Status code.
*
******************************************************************************/
int mgmtFrameRecv = 0;
int svcFrameRecv = 0;
int32_t Linklayer_PktHandler(L2_INST* instPtr, L2_FRAME_TYPE frameType) {
ASSERT(instPtr != NULL);
DBG_INFO("Link layer handling packet...\n");
int32_t Status = SUCCESS;
if (instPtr->dataAvail == false) {
return FAILURE;
}
switch (frameType) {
case L2_INTER_SCAN_FRAME:
case L2_INTRA_SCAN_FRAME:
case L2_INTER_BM_FRAME:
case L2_INTRA_BM_FRAME:
case L2_INTER_W2_ACQ_FRAME:
case L2_INTRA_W2_ACQ_FRAME:
Status = ScanNet_PktHandler(instPtr);
break;
case L2_INTER_MGMT_FRAME:
case L2_INTRA_MGMT_FRAME:
case L2_INTER_TSYNC_FRAME:
case L2_INTRA_TSYNC_FRAME:
// TODO:
if(frameType == L2_INTRA_MGMT_FRAME){
if (instPtr->buffSwitch == 0) {
memcpy(instPtr->mgmtMsgRecvBuff0 + (size_t)(instPtr->mgmtMsgRecvCnt0*(MGMT_MSG_LEN*ARRAY_SIZE(intraMgmtFrameMsgs)/8)),
instPtr->recvPktData, (size_t)(MGMT_MSG_LEN*ARRAY_SIZE(intraMgmtFrameMsgs)/8));
instPtr->mgmtMsgRecvCnt0++;
}
else {
memcpy(instPtr->mgmtMsgRecvBuff1+ (size_t)(instPtr->mgmtMsgRecvCnt1*(MGMT_MSG_LEN*ARRAY_SIZE(intraMgmtFrameMsgs)/8)),
instPtr->recvPktData, (size_t)(MGMT_MSG_LEN*ARRAY_SIZE(intraMgmtFrameMsgs)/8));
instPtr->mgmtMsgRecvCnt1++;
}
}
mgmtFrameRecv++;
Status = MgmtNet_PktHandler(instPtr);
break;
case L2_INTER_SVC_FRAME:
case L2_INTRA_SVC_FRAME:
// TODO:
if(frameType == L2_INTRA_SVC_FRAME){
if (instPtr->buffSwitch == 0) {
memcpy(instPtr->svcMsgRecvBuff0 + (size_t) (instPtr->svcMsgRecvCnt0 * (INTRA_SVC_FRAME_LENGTH_MAX)),
instPtr->recvPktData, (size_t)(INTRA_SVC_FRAME_LENGTH_MAX));
instPtr->svcMsgRecvCnt0 ++;
}
else {
memcpy(instPtr->svcMsgRecvBuff1+ (size_t)(instPtr->svcMsgRecvCnt1 * (INTRA_SVC_FRAME_LENGTH_MAX)),
instPtr->recvPktData, (size_t)(INTRA_SVC_FRAME_LENGTH_MAX));
instPtr->svcMsgRecvCnt1 ++;
}
}
svcFrameRecv++;
Status = ServiceNet_PktHandler(instPtr);
break;
default:
DBG_WARNING("L2FrameHandler: UNKNOWN L2-FrameType %d", frameType);
Status = FAILURE;
break;
}
return Status;
}
/*****************************************************************************/
/**
* @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;
// FIXME: Consider time wrapping.
uint32_t currTime = TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr)/L2_SLOTS_PER_FRAME;
if(currTime < instPtr->netStartTime) {
DBG_WARNING("Linklayer not start yet, current time unit: %u, start time unit: %u.\n",
currTime, instPtr->netStartTime);
return EIGNORE;
}
// Determine which routine entry is going to be performed.
tableIndx = L2_GetCurrentFrameNum(instPtr) % instPtr->rtneConfig.rtnePrd;
entryIndx = L2_GetCurrentSlotNum(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: %u-%u, Routine period: %u.\n", tableIndx, entryIndx, instPtr->rtneConfig.rtnePrd);
// Implement a RTT procedure.
RTT_Proc(instPtr);
switch (rtneEntry.slotType) {
case SLOT_IDLE:
// Skip a 5ms slot.
Status = SUCCESS;
DBG_INFO("Skipping idle slot (5ms)...\n");
break;
case SLOT_INTER_SCAN_ACQ:
case SLOT_INTRA_SCAN_ACQ:
case SLOT_INTER_SCAN_BM:
case SLOT_INTRA_SCAN_BM:
case SLOT_INTER_SCAN_2W:
case SLOT_INTRA_SCAN_2W:
Status = ScanNet_Routine(instPtr, &rtneEntry);
break;
case SLOT_INTER_SVC:
case SLOT_INTRA_SVC:
Status = ServiceNet_Routine(instPtr, &rtneEntry);
break;
case SLOT_INTER_MGMT:
case SLOT_INTRA_MGMT:
case SLOT_INTER_TSYNC:
case SLOT_INTRA_TSYNC:
Status = MgmtNet_Routine(instPtr, &rtneEntry);
break;
default:
DBG_ERROR("UNKNOWN slot type [%d].\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);
}
// FIXME: Increase TTL counter
if (instPtr->mainState != INIT_STATE)
{
if ( IsNodeInList (instPtr->nodeList, rtneEntry.src0) )
{
// IncNodeTTL(usedSlots, rtneEntry.src0 );
}
}
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;
if(instPtr->isEnable == false) {
DBG_INFO("######## Link Layer is not Enabled ########\n");
return SUCCESS;
}
DBG_INFO("######## Current frameNum: %u, SlotNo: %u ########\n",
instPtr->frameNum.curr, instPtr->slotNum.curr);
// Update frame status.
L2_FrameStateUpdate(instPtr);
// Handle frame received in last slot.
if(L2_isDataAvail(instPtr) == true){
Linklayer_PktHandler(instPtr, L2_GetLastRcvFrameType(instPtr));
}
// Run Link layer routine, setup next slot procedure.
if (instPtr->myInfo.nodeType == HEAD_NODE) {
Phy_SetMode(instPtr->config.phyInstPtr, PHY_MODE_PULL);
Status = Linklayer_Routine(instPtr);
}
else { //MEMBER_NODE
if (L2_isCxn2Net(instPtr)) {
Phy_SetMode(instPtr->config.phyInstPtr, PHY_MODE_PULL);
Status = Linklayer_Routine(instPtr);
}
else {
Phy_SetMode(instPtr->config.phyInstPtr, PHY_MODE_LISTEN);
Status = ScanNet_Proc(instPtr);
}
}
// Check if previous runs has error occurred.
if (Status != SUCCESS) {
return Status;
}
// Check and execute scheduled event.
L2_EventPoolHandler(instPtr);
// Update slot number.
L2_UpdateSlotNum(instPtr);
// Update link layer state.
instPtr->mainState = instPtr->nextState;
// Upload data per 500ms
if (instPtr->slotNum.next % DATA_STORE_INTERVAL == 0) {
instPtr->buffSwitch = (instPtr->buffSwitch == 0) ? 1 : 0;
if(instPtr->buffSwitch == 0){
instPtr->mgmtMsgRecvCnt0 = 0;
instPtr->svcMsgRecvCnt0 = 0;
}
else{
instPtr->mgmtMsgRecvCnt1 = 0;
instPtr->svcMsgRecvCnt1 = 0;
}
}
return SUCCESS;
}