/*****************************************************************************/ /** * Description: main.c * * Date: 2021-11-13 13:19 * Last Editors: Fan Hao * Last Edit Time: [2022-03-28 20:32] * * Revisions: Rev 0.0 * History: * [2021-11-13]: Initial edition. * [2022-03-28]: Add bit error test mode. * * Copyright(c) 2021 Beijing Institute of Technology. * Lab of Communication and Networking * ******************************************************************************/ /***************************** Include Files *********************************/ #include #include "config/app_config.h" #include "xscugic.h" // The generic interrupt controller driver component #include "xil_exception.h" // ARM Cortex A9 specific exception related APIs #include "xgpio.h" #include "sleep.h" // Sleep APIs for Cortex A9 #include "xil_cache.h" #include "linklayer/linklayer814.h" #include "linklayer/msg_def.h" #include "phy_ctrl/phy_ctrl.h" #include "bit_array/bit_array.h" #include "mpc/mpc_ctrl.h" #ifdef _MPC_CTRL #include "./mpc/mpc_ctrl.h" #endif #include "hardware/headless.h" /************************** Constant Definitions *****************************/ L2_CONFIG l2Config = { .myType = L2_NODE_MEMBER, .isInterHead = false, .myId = 2, .clustId = 1, .headId = 1, .bkpHeadId = 1, .netScale = 2, .phyInstPtr = NULL, .tmcInstPtr = NULL}; TIMECTRL_CONFIG tmcConfig = { .baseAddr = TIME_CONTROLLER_BASEADDR, .reset = 10}; PHY_CONFIG l1Config = { .devId = PHY_DEVICE_ID, .txBramId = TXBUFF_BRAM_ID, .rxBramId = RXBUFF_BRAM_ID, .antBramId = ANTCONFIG_BRAM_ID, .baseAddr = PHY_CTRL_BASEADDR}; MPC_CONFIG mpcConfig = { .bramDevId = MPC_PCIE_BRAM_ID, .msgLenMax = MPC_BUFFER_LENGTH // byte }; static bool mpcStatusUpAssert = false; /************************** Function Prototypes ******************************/ int SetupInterruptSystem(XScuGic *instPtr, uint32_t devId); void PhysicalIntr_Handler(void *callBackRef); void PeriodicPull_Handler(void *callBackRef); #ifdef _MPC_CTRL void MPC_IntrHandler(void *callBackRef); #endif /*********************** Driver Instance Definitions **************************/ TIMECTRL_INST *tmcInstPtr = NULL; PHY_INST *phyInstPtr = NULL; L2_INST *linkInstPtr = NULL; static XScuGic gicInst; // General interrupt controller intance // FIXME: Only for test... XGpio configGpio; /* The Instance of the GPIO Driver */ /****************************************************************************/ /** * This function is responsible for initializing the SCUGIC instance, looking * for the device configuration based on the unique device ID, initializing a * SCUGIC instance, and initialize the interrupt at IRQ_F2P[0:0] * * @param devId is the XPAR__DEVICE_ID value from * "xparameters.h". * @param instPtr is a reference to the XScuGic driver Instance. * * @return SUCCESS if initialize successful. * FAILURE if initialization failed. * *****************************************************************************/ int SetupInterruptSystem(XScuGic *instPtr, uint32_t devId) { XScuGic_Config *configPtr; int Status; uint32_t intrState; // Initialize the GIC instance. configPtr = XScuGic_LookupConfig(devId); Status = XScuGic_CfgInitialize(instPtr, configPtr, configPtr->CpuBaseAddress); if (Status != SUCCESS) { return Status; } // Perform a self-test to ensure that the hardware was built correctly. Status = XScuGic_SelfTest(instPtr); if (Status != SUCCESS) { return Status; } // Clear any pending interrupt flags intrState = XScuGic_CPUReadReg(instPtr, XSCUGIC_INT_ACK_OFFSET); XScuGic_CPUWriteReg(instPtr, XSCUGIC_EOI_OFFSET, intrState); /* * FOR PRIORITY: * 0 is highest priority, 0xF8(248) is lowest. There are 32 priority levels * supported with a step of 8. Hence the supported priorities are 0, 8, 16, * 32, 40 ..., 248. * * FOR TRIGGER: * SFI Read Only b10 always * PPI Read Only depending on how the PPIs are configured. * b01 Active HIGH level sensitive * b11 Rising edge sensitive * SPI LSB is read only. * b01 Active HIGH level sensitive * b11 Rising edge sensitive */ /* Set the priority of IRQ_F2P[1:1] to 0x00 (highest) and a trigger for a * rising edge 0x03. */ // Initialize physical layer interrupt. XScuGic_SetPriorityTriggerType(instPtr, PHY_INTR_ID, 0x00, 0x03); // Connect the interrupt service routine isr1 to the interrupt controller Status = XScuGic_Connect(instPtr, PHY_INTR_ID, (Xil_ExceptionHandler)PhysicalIntr_Handler, (void *)phyInstPtr); if (Status != SUCCESS) { return Status; } // Initialize physical layer interrupt. XScuGic_SetPriorityTriggerType(instPtr, PERIODIC_5MS_INTR_ID, 0x00, 0x03); // Connect the interrupt service routine isr1 to the interrupt controller Status = XScuGic_Connect(instPtr, PERIODIC_5MS_INTR_ID, (Xil_ExceptionHandler)PeriodicPull_Handler, (void *)linkInstPtr); if (Status != SUCCESS) { return Status; } #ifdef _MPC_CTRL // Initialize MPC interrupt. XScuGic_SetPriorityTriggerType(instPtr, MPC_RX_DONE_INTR_ID, 0x00, 0x03); // Connect the interrupt service routine isr1 to the interrupt controller Status = XScuGic_Connect(instPtr, MPC_RX_DONE_INTR_ID, (Xil_ExceptionHandler)MPC_IntrHandler, (void *)mpcInstPtr); if (Status != XST_SUCCESS) { return Status; } XScuGic_Enable(instPtr, MPC_RX_DONE_INTR_ID); #endif XScuGic_Enable(instPtr, PHY_INTR_ID); XScuGic_Enable(instPtr, PERIODIC_5MS_INTR_ID); /* Initialize the exception table and register the interrupt controller * handler with the exception table */ Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, (void *)instPtr); // Enable non-critical exceptions Xil_ExceptionEnable(); return Status; } // SetupInterruptSystem #ifdef _MPC_CTRL void MPC_PCIESentStart() { uint32_t GpioConfig = XGpio_DiscreteRead(&configGpio, 2); GpioConfig ^= 0x00000002; XGpio_DiscreteWrite(&configGpio, 2, GpioConfig); } /*****************************************************************************/ /** * @brief Handler of mater pc contrl interrupt. * * @param CallBackRef A pointer to corresponding mpcInstPtr instance. * * @return None. * ******************************************************************************/ void MPC_IntrHandler(void *CallBackRef) { MPC_MsgHandler(mpcInstPtr); } #endif /*****************************************************************************/ /** * @brief Handler of physical layer interrupt. * * @param CallBackRef A pointer to corresponding physical layer instance. * * @return None. * ******************************************************************************/ void PhysicalIntr_Handler(void *callBackRef) { Phy_UpdateState(phyInstPtr); if (phyInstPtr->TOR.curr == PHY_TOR_TX) { switch (phyInstPtr->frameType.curr) { case L1_1M2BPS_5MS_FRAME: mpcRecord->frame1Sent++; break; case L1_200KBPS_5MS_FRAME: mpcRecord->frame2Sent++; break; case L1_40KBPS_10MS_FRAME: mpcRecord->frame3Sent++; break; case L1_40KBPS_20MS_FRAME: mpcRecord->frame4Sent++; break; case L1_10KBPS_20MS_FRAME: mpcRecord->frame5Sent++; break; case L1_2KBPS_100MS_FRAME: mpcRecord->frame6Sent++; break; case L1_10KBPS_10MS_FRAME: mpcRecord->frame7Sent++; break; case L1_2KBPS_20MS_FRAME: mpcRecord->frame8Sent++; break; default: break; } } if (phyInstPtr->TOR.last == PHY_TOR_RX && phyInstPtr->isFrameSync) { switch (phyInstPtr->frameType.last) { case L1_1M2BPS_5MS_FRAME: mpcRecord->frame1Recv++; break; case L1_200KBPS_5MS_FRAME: mpcRecord->frame2Recv++; break; case L1_40KBPS_10MS_FRAME: mpcRecord->frame3Recv++; break; case L1_40KBPS_20MS_FRAME: mpcRecord->frame4Recv++; break; case L1_10KBPS_20MS_FRAME: mpcRecord->frame5Recv++; break; case L1_2KBPS_100MS_FRAME: mpcRecord->frame6Recv++; break; case L1_10KBPS_10MS_FRAME: mpcRecord->frame7Recv++; break; case L1_2KBPS_20MS_FRAME: mpcRecord->frame8Recv++; break; default: break; } } } /****************************************************************************/ /** * Handler of periodic 5ms interrupt * * @param callBackRef is the linklayer instance pointer. * * @return None. * *****************************************************************************/ void PeriodicPull_Handler(void *callBackRef) { int32_t Status; Status = Linklayer_Proc(linkInstPtr); if (Status != SUCCESS) { DBG_ERROR("Link layer runs failed, with error code: %ld\n", Status); _nop_(); } if (linkInstPtr->slotNum.next % DATA_STORE_INTERVAL == 1) { mpcStatusUpAssert = true; mpcRecord->frame1Cnt = mpcRecord->frame1Recv - mpcRecord->frame1CntLast; mpcRecord->frame2Cnt = mpcRecord->frame2Recv - mpcRecord->frame2CntLast; mpcRecord->frame3Cnt = mpcRecord->frame3Recv - mpcRecord->frame3CntLast; mpcRecord->frame4Cnt = mpcRecord->frame4Recv - mpcRecord->frame4CntLast; mpcRecord->frame5Cnt = mpcRecord->frame5Recv - mpcRecord->frame5CntLast; mpcRecord->frame6Cnt = mpcRecord->frame6Recv - mpcRecord->frame6CntLast; mpcRecord->frame7Cnt = mpcRecord->frame7Recv - mpcRecord->frame7CntLast; mpcRecord->frame8Cnt = mpcRecord->frame8Recv - mpcRecord->frame8CntLast; // Store last time received frame number mpcRecord->frame1CntLast = mpcRecord->frame1Recv; mpcRecord->frame2CntLast = mpcRecord->frame2Recv; mpcRecord->frame3CntLast = mpcRecord->frame3Recv; mpcRecord->frame4CntLast = mpcRecord->frame4Recv; mpcRecord->frame5CntLast = mpcRecord->frame5Recv; mpcRecord->frame6CntLast = mpcRecord->frame6Recv; mpcRecord->frame7CntLast = mpcRecord->frame7Recv; mpcRecord->frame8CntLast = mpcRecord->frame8Recv; } uint32_t GpioConfig = XGpio_DiscreteRead(&configGpio, 2); if (L2_isDataAvail(linkInstPtr) == true) { GpioConfig ^= 0x00000001; } XGpio_DiscreteWrite(&configGpio, 2, GpioConfig); } // PeriodicPull_Handler /*****************************************************************************/ /** * @brief Main function, initialize all the device needed, initialize * interrupt system, halt in while(1) wait for event interrupt. * * @param None. * * @return * ******************************************************************************/ int main(void) { int Status; Status = HARDWARE_initialize(); if (Status == SUCCESS) { DBG_PRINT("Hardware Init SUCCESS! \n"); } else { DBG_PRINT("Hardware Init FAILED! \n"); return Status; } Status = XGpio_Initialize(&configGpio, XPAR_CONFIG_GPIO_DEVICE_ID); if (Status != SUCCESS) { DBG_PRINT("Config Gpio Initialization Failed\n"); return FAILURE; } XGpio_SetDataDirection(&configGpio, 1, 0xFFFFFFFF); XGpio_SetDataDirection(&configGpio, 2, 0x00000000); // Init time controller Status = TimeCtrl_Init(&tmcInstPtr, &tmcConfig); if (Status == SUCCESS) { DBG_PRINT("TmcCtrl Init SUCCESS! \n"); } else { DBG_PRINT("TmcCtrl Init FAILED! \n"); return Status; } // Init physical layer Status = Phy_InstInit(&phyInstPtr, &l1Config); if (Status == SUCCESS) { DBG_PRINT("PhyCtrl Init SUCCESS! \n"); } else { DBG_PRINT("PhyCtrl Init FAILED! \n"); return Status; } // Update l2 config l2Config.phyInstPtr = phyInstPtr; l2Config.tmcInstPtr = tmcInstPtr; Status = Linklayer_Init(&linkInstPtr, &l2Config); if (Status == SUCCESS) { DBG_PRINT("LinkLayer Init SUCCESS! \n"); } else { DBG_PRINT("Linklayer Init FAILED! \n"); return Status; } // Init MPC Status = MPC_Init(&mpcInstPtr, &mpcConfig); if (Status == SUCCESS) { DBG_PRINT("MPC Init SUCCESS! \n"); } else { DBG_PRINT("MPC Init FAILED! \n"); return Status; } // Initialize GIC. Status = SetupInterruptSystem(&gicInst, SCUGIC_DEVICE_ID); if (Status == SUCCESS) { DBG_PRINT("Intc Init SUCCESS! \n"); } else { DBG_PRINT("Intc Init FAILED! \n"); return Status; } DBG_PRINT("Starting Physical Layer..."); Phy_Start(phyInstPtr); // FIXME: only for debug, linklayer should be start by MPC Linklayer_Start(linkInstPtr); while (true) { if (mpcStatusUpAssert == true) { mpcStatusUpAssert = false; if (linkInstPtr->buffSwitch == 0) { MPC_StateUpload(mpcInstPtr, linkInstPtr->mgmtMsgRecvBuff1, linkInstPtr->mgmtMsgRecvCnt1, linkInstPtr->svcMsgRecvBuff1, linkInstPtr->svcMsgRecvCnt1, &(linkInstPtr->mgmtNetFSM->mgmtMsgLog)); } else { MPC_StateUpload(mpcInstPtr, linkInstPtr->mgmtMsgRecvBuff0, linkInstPtr->mgmtMsgRecvCnt0, linkInstPtr->svcMsgRecvBuff0, linkInstPtr->svcMsgRecvCnt0, &(linkInstPtr->mgmtNetFSM->mgmtMsgLog)); } } } } // main