/*****************************************************************************/ /** * 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 #include #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); /** * @brief helper function to update linkelayer state */ 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; } /** * @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 %u\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 %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 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. * ******************************************************************************/ void L2_FrameStateUpdate(L2_INST *instPtr) { ASSERT(instPtr != NULL); PHY_INST *phyRef = instPtr->config.phyInstPtr; // 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); instPtr->log.frameRecv++; 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: instPtr->log.bmRecvCnt++; if (L2_CrcCheck(instPtr->recvPktData, BM_MSG_CRC_OFFSET / 8, BM_MSG_CRC_OFFSET / 8, L2_CRC8_31) == true) { L2_DataAvailUpdate(instPtr, true); instPtr->log.bmCorrectCnt++; } else { L2_DataAvailUpdate(instPtr, false); } break; case L2_INTRA_W2_ACQ_FRAME: instPtr->log.w2acqRecvCnt++; if (L2_CrcCheck(instPtr->recvPktData, W2ACQ_FRAME_CRC_DLEN, W2ACQ_FRAME_CRC_POS, L2_CRC16_8005) == true) { L2_DataAvailUpdate(instPtr, true); instPtr->log.w2acqCorrectCnt++; } else { L2_DataAvailUpdate(instPtr, false); } break; case L2_INTRA_MGMT_FRAME: instPtr->log.mgmtRecvCnt++; L2_DataAvailUpdate(instPtr, true); instPtr->log.mgmtCorrectCnt++; break; case L2_INTRA_TSYNC_FRAME: instPtr->log.tsyncRecvCnt++; L2_DataAvailUpdate(instPtr, true); instPtr->log.tsyncCorrectCnt++; break; case L2_INTRA_SVC_FRAME: instPtr->log.svcRecvCnt++; if (L2_CrcCheck(instPtr->recvPktData, PDUH0_HEADER_CRC_OFFSET / 8, PDUH0_HEADER_CRC_OFFSET / 8, L2_CRC8_31) == true) { L2_DataAvailUpdate(instPtr, true); instPtr->log.svcCorrectCnt++; } else { L2_DataAvailUpdate(instPtr, false); } break; default: L2_DataAvailUpdate(instPtr, false); break; } if (L2_isDataAvail(instPtr)) { instPtr->log.frameCorrect++; } } /*****************************************************************************/ /** * @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; if (frameType < L2_INTER_SCAN_FRAME || frameType > L2_INTRA_SVC_FRAME) { return FAILURE; } // logging if (txrxMode == L2_TOR_TX) { instPtr->log.frameTx++; switch (frameType) { case L2_INTRA_BM_FRAME: instPtr->log.bmTxCnt++; break; case L2_INTRA_W2_ACQ_FRAME: instPtr->log.w2acqTxCnt++; break; case L2_INTRA_MGMT_FRAME: instPtr->log.mgmtTxCnt++; break; case L2_INTRA_TSYNC_FRAME: instPtr->log.tsyncTxCnt++; break; case L2_INTRA_SVC_FRAME: instPtr->log.svcTxCnt++; break; default: break; } } else if (txrxMode == L2_TOR_RX) { instPtr->log.frameRx++; switch (frameType) { case L2_INTRA_BM_FRAME: instPtr->log.bmRxCnt++; break; case L2_INTRA_W2_ACQ_FRAME: instPtr->log.w2acqRxCnt++; break; case L2_INTRA_MGMT_FRAME: instPtr->log.mgmtRxCnt++; break; case L2_INTRA_TSYNC_FRAME: instPtr->log.tsyncRxCnt++; break; case L2_INTRA_SVC_FRAME: instPtr->log.svcRxCnt++; break; default: break; } } #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. // Frame types shift (last <- curr <- next) L2_RcdShift(&(instPtr->frame), frameType); L2_RcdShift(&(instPtr->tor), 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. * ******************************************************************************/ #ifndef 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(L2_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(L2_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(L2_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(L2_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)->rtneConfig.last = NULL; (*instPtr)->rtneConfig.curr = NULL; (*instPtr)->rtneConfig.next = NULL; (*instPtr)->isEnable = false; (*instPtr)->cxn2Net = 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_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 = 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 buffer count (*instPtr)->mgmtMsgRecvCnt0 = 0; (*instPtr)->mgmtMsgRecvCnt1 = 0; (*instPtr)->svcMsgRecvCnt0 = 0; (*instPtr)->svcMsgRecvCnt1 = 0; (*instPtr)->buffSwitch = 0; Status = L2_CreateSchedEventPool(&((*instPtr)->schdEventPool)); if (Status != SUCCESS) { DBG_ERROR("L2_CreateSchedEventPool runs failed, with error code: %d.\n", Status); goto error; } Status = L2_NodeList_Init(&((*instPtr)->nodeList)); if (Status != SUCCESS) { DBG_ERROR("NodeList_Init runs failed, with error code: %d.\n", Status); goto error; } 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 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 = 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_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 = 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 buffer count instPtr->mgmtMsgRecvCnt0 = 0; instPtr->mgmtMsgRecvCnt1 = 0; instPtr->svcMsgRecvCnt0 = 0; instPtr->svcMsgRecvCnt1 = 0; instPtr->buffSwitch = 0; // Reset according instance L2_ClearSchedEventPool(instPtr->schdEventPool); L2_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 L2_DestroySchedEventPool(instPtr->schdEventPool); L2_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 (L2_GetNodeType(instPtr) != L2_NODE_HEAD) { instPtr->cxn2Net = true; instPtr->netStartTime = *((uint32_t *)l2Event->msg); } else { // Head node UpdateMainSate(instPtr, L2_NORMAL_STATE); } break; } case L2_EV_TIME_SYNC: { DBG_INFO("Event L2_EV_TIME_SYNC asserted....\n"); break; } case L2_EV_RTT_RECV_UPDATE: DBG_INFO("Event L2_EV_RTT_RECV_UPDATE asserted....\n"); RTT_FsmUpdate(instPtr, L2_TOR_RX); 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", L2_GetHeadId(instPtr)); 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 == L2_INIT_STATE) { // Reset scan net FMS for next scan process. ScanNet_Reset(instPtr->scanNetFSM); UpdateMainSate(instPtr, L2_NORMAL_STATE); instPtr->rtneConfig.rtneTable = normalTable; instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable); } else if (instPtr->nextState == L2_NORMAL_STATE) { instPtr->rtneConfig.rtneTable = normalTable; instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(normalTable); } else if (instPtr->nextState == L2_SEEK_STATE) { instPtr->rtneConfig.rtneTable = seekTable; instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(seekTable); } else if (instPtr->nextState == L2_INTRA_SEEK_STATE) { instPtr->rtneConfig.rtneTable = intraSeekTable; instPtr->rtneConfig.rtnePrd = ARRAY_SIZE(intraSeekTable); } else if (instPtr->nextState == L2_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); 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: 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: 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\n", 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 nextTimeUnit = (TimeCtrl_GetIntCnt(instPtr->config.tmcInstPtr) + 1) / L2_SLOTS_PER_FRAME; if (nextTimeUnit < instPtr->netStartTime) { DBG_WARNING("Linklayer not start yet, next time unit: %u, start time unit: %u.\n", nextTimeUnit, instPtr->netStartTime); return EIGNORE; } // 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: %u-%u, Routine period: %u.\n", tableIndx, entryIndx, instPtr->rtneConfig.rtnePrd); switch (rtneEntry.slotType) { case L2_SLOT_IDLE: // Skip a 5ms slot. Status = SUCCESS; DBG_INFO("Skipping idle slot (5ms)...\n"); break; case L2_SLOT_INTER_SCAN_ACQ: case L2_SLOT_INTRA_SCAN_ACQ: case L2_SLOT_INTER_SCAN_BM: case L2_SLOT_INTRA_SCAN_BM: case L2_SLOT_INTER_SCAN_2W: case L2_SLOT_INTRA_SCAN_2W: Status = ScanNet_Routine(instPtr, &rtneEntry); break; case L2_SLOT_INTER_SVC: case L2_SLOT_INTRA_SVC: Status = ServiceNet_Routine(instPtr, &rtneEntry); break; case L2_SLOT_INTER_MGMT: case L2_SLOT_INTRA_MGMT: case L2_SLOT_INTER_TSYNC: case L2_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 != L2_INIT_STATE) { // if ( L2_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; } // Update slot number. L2_UpdateSlotNum(instPtr); 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_GetLastFrameType(instPtr)); } // Run Link layer routine, setup next slot procedure. if (L2_GetNodeType(instPtr) == L2_NODE_HEAD) { Phy_SetMode(instPtr->config.phyInstPtr, PHY_MODE_PULL); Status = Linklayer_Routine(instPtr); } else { // L2_NODE_MEMBER 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 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; }