Files
hj_datalink/src/main.c
T

581 lines
16 KiB
C

/*****************************************************************************/
/**
* Description: main.c
*
* Date: 2023-05-07 13:19
* Last Edit Time: [2023-05-07 20:32]
*
* Revisions: Rev 0.0
* History:
* [2023-05-07]: Initial edition.
*
* Copyright(c) 2024 Beijing Institute of Technology.
*
******************************************************************************/
/***************************** Include Files *********************************/
// Standard
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
// Xilinx
#include "xscugic.h"
#include "drivers/platform/xilinx_irq.h"
#include "drivers/platform/xilinx_timer.h"
// App
#include "common.h"
#include "error.h"
#include "timer.h"
#include "hwconfig.h"
#include "config/app_config.h"
#include "dev_profile/dev_profile.h"
#include "systembus/systembus.h"
#include "networking/phy_layer/phy_layer.h"
#include "networking/link_layer/link_layer.h"
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
#include <metal/log.h>
#endif
/************************** Function Prototypes ******************************/
int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr);
void Phy_IntrHandler(void *context);
void PeriodicPoll_Handler(void *callBackRef);
void AppTimer_IntrHandler(void *context);
void Systembus_RxIntrHandler(void *context);
void Systembus_TxIntrHandler(void *context);
/************************** Constant Definitions *****************************/
struct callback_desc phy_callback_desc = {
.callback = Phy_IntrHandler,
.ctx = NULL
};
struct callback_desc periodicpoll_callback_desc = {
.callback = PeriodicPoll_Handler,
.ctx = NULL
};
struct callback_desc sysbus_rx_callback_desc = {
.callback = Systembus_RxIntrHandler,
.ctx = NULL
};
struct callback_desc sysbus_tx_callback_desc = {
.callback = Systembus_TxIntrHandler,
.ctx = NULL
};
struct callback_desc apptimer_callback_desc = {
.callback = AppTimer_IntrHandler,
.ctx = NULL
};
//L2_CONFIG linkConfig = {
// .myType = L2_NODE_HEAD,
// .clustId = 1U,
// .myId = 1U,
// .headId = L2_HEAD_ID,
// .netScale = L2_NET_SCALE,
// .initTable = initRoutTable,
// .normalTable = normalRoutTable1,
// .serviceRate = L2_SVC_512K,
// .phyInstPtr = NULL, // physical layer reference
// .tmcInstPtr = NULL
//};
L2_CONFIG linkConfig = {
.myType = L2_NODE_MEMBER,
.clustId = 1U,
.myId = 2U,
.headId = L2_HEAD_ID,
.netScale = L2_NET_SCALE,
.initTable = initRoutTable,
.normalTable = normalRoutTable1,
.serviceRate = L2_SVC_512K,
.phyInstPtr = NULL, // physical layer reference
.tmcInstPtr = NULL
};
static PHY_CONFIG phyConfig = {
.devId = PHY_DEVICE_ID,
.baseAddr = PHY_BASEADDR,
.antBramId = PHY_ANTCONFIG_BRAM_DEVICE_ID,
.txBramId = PHY_TXBUFF_BRAM_DEVICE_ID,
.rxBramId = PHY_RXBUFF_BRAM_DEVICE_ID,
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
.hwSysmonId = PHY_HW_SYSMON_DEVICE_ID,
.get_clk_state = Hardware_GetLMK04828LockStatus,
.get_ad_lock_state = NULL,
.get_ad0_temp = NULL,
.get_ad1_temp = NULL
#else
.hwXadcId = PHY_HW_XADC_DEVICE_ID,
.get_clk_state = Hardware_GetAD9528LockStatus,
.get_ad_lock_state = Hardware_GetAD9361LockStatus,
.get_ad0_temp = Hardware_GetAD9361Temp_1,
.get_ad1_temp = Hardware_GetAD9361Temp_2
#endif
};
TMC_CONFIG tmcConfig = {
.baseAddr = TIME_CONTROLLER_BASEADDR,
.reset = 10U
};
static SYSBUS_CONFIG sysbusConfig = {
.baseAddr = SYSBUS_BASE_ADDR,
.txQueueMax = 32U,
.rxQueueMax = 32U
};
static SYSMON_CONFIG sysmonConfig = {
.sendQueueMax = 16U,
.recvQueueMax = 16U
};
/*********************** Driver Instance Definitions **************************/
static struct irq_ctrl_desc *intcDescPtr = NULL; // General interrupt controller descriptor
static struct timer_desc *logTmPtr = NULL;
SYSBUS *sysbusDescPtr = NULL;
static PHY_INST *phyInstPtr = NULL;
static TMC_INST *tmcInstPtr = NULL;
L2_INST *linkInstPtr = NULL;
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
void MetalLogHandler(enum metal_log_level level, const char *format, ...)
{
char msg[1024];
va_list args;
static const char * const level_strs[] = {
"metal: emergency: ",
"metal: alert: ",
"metal: critical: ",
"metal: error: ",
"metal: warning: ",
"metal: notice: ",
"metal: info: ",
"metal: debug: ",
};
va_start(args, format);
vsnprintf(msg, sizeof(msg), format, args);
va_end(args);
if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG)
level = METAL_LOG_EMERGENCY;
printf("%s%s", level_strs[level], msg);
}
#endif
/****************************************************************************/
/**
* 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 intcDesc A pointer to INTC descriptor
*
* @return SUCCESS if initialize successful.
* FAILURE if initialization failed.
*
*****************************************************************************/
int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr)
{
int32_t Status;
struct xil_irq_desc *xil_dev;
Status = irq_ctrl_init(&descPtr, &intc_init_param);
if (Status != SUCCESS)
{
DBG_ERROR("Intc Init FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
xil_dev = (struct xil_irq_desc *)(descPtr->extra);
// Clear any pending interrupt flags
uint32_t intrState = XScuGic_CPUReadReg((XScuGic *)(xil_dev->instance), XSCUGIC_INT_ACK_OFFSET);
XScuGic_CPUWriteReg((XScuGic *)(xil_dev->instance), XSCUGIC_EOI_OFFSET, intrState);
/* Initialize physical layer interrupt. */
// Set interrupt trigger level
Status = irq_trigger_level_set(descPtr, PHY_INTR_ID, IRQ_EDGE_RISING);
if (Status != SUCCESS)
{
DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Set highest interrupt priority
Status = irq_set_priority(descPtr, PHY_INTR_ID, 0x08);
if (Status != SUCCESS)
{
DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Connect the interrupt service routine isr1 to the interrupt controller
Status = irq_register_callback(descPtr, PHY_INTR_ID, &phy_callback_desc);
if (Status != SUCCESS)
{
DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
/* Initialize linklayer layer interrupt. */
// Set interrupt trigger level
Status = irq_trigger_level_set(descPtr, PERIODIC_5MS_INTR_ID, IRQ_EDGE_RISING);
if (Status != SUCCESS)
{
DBG_ERROR("PERIODIC_5MS_INTR_ID trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Set highest interrupt priority
Status = irq_set_priority(descPtr, PERIODIC_5MS_INTR_ID, 0x00);
if (Status != SUCCESS)
{
DBG_ERROR("PERIODIC_5MS_INTR_ID priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Connect the interrupt service routine isr1 to the interrupt controller
Status = irq_register_callback(descPtr, PERIODIC_5MS_INTR_ID, &periodicpoll_callback_desc);
if (Status != SUCCESS)
{
DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
/* Initialize system bus interrupt. */
// Set interrupt trigger level
Status = irq_trigger_level_set(descPtr, SYSBUS_TX_INTR_ID, IRQ_EDGE_RISING);
if (Status != SUCCESS)
{
DBG_ERROR("SYSBUS_TX_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Set interrupt priority
Status = irq_set_priority(descPtr, SYSBUS_TX_INTR_ID, 0x10);
if (Status != SUCCESS)
{
DBG_ERROR("SYSBUS_TX_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Connect the interrupt service routine isr1 to the interrupt controller
Status = irq_register_callback(descPtr, SYSBUS_TX_INTR_ID, &sysbus_tx_callback_desc);
if (Status != SUCCESS)
{
DBG_ERROR("SYSBUS_TX_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Set interrupt trigger level
Status = irq_trigger_level_set(descPtr, SYSBUS_RX_INTR_ID, IRQ_EDGE_RISING);
if (Status != SUCCESS)
{
DBG_ERROR("SYSBUS_RX_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Set interrupt priority
Status = irq_set_priority(descPtr, SYSBUS_RX_INTR_ID, 0x18);
if (Status != SUCCESS)
{
DBG_ERROR("SYSBUS_RX_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Connect the interrupt service routine isr1 to the interrupt controller
Status = irq_register_callback(descPtr, SYSBUS_RX_INTR_ID, &sysbus_rx_callback_desc);
if (Status != SUCCESS)
{
DBG_ERROR("SYSBUS_RX_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
/* Initialize Scu timer interrupt. */
// Connect the interrupt service routine isr1 to the interrupt controller
Status = irq_register_callback(descPtr, APPTIMER_INTR_ID, &apptimer_callback_desc);
if (Status != SUCCESS)
{
DBG_ERROR("APPTIMER_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Enable interrupts
irq_enable(descPtr, PHY_INTR_ID);
irq_enable(descPtr, PERIODIC_5MS_INTR_ID);
irq_enable(descPtr, SYSBUS_RX_INTR_ID);
irq_enable(descPtr, SYSBUS_TX_INTR_ID);
irq_enable(descPtr, APPTIMER_INTR_ID);
// Enable Exceptions
Status = irq_global_enable(descPtr);
if (Status != SUCCESS)
{
DBG_ERROR("IRQ global enable FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
return SUCCESS;
} // SetupInterruptSystem
/****************************************************************************/
/**
* This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1]
* tells CPU that the data in OCM is ready!
*
* @param context
*
* @return None.
*
*****************************************************************************/
void Phy_IntrHandler(void *context)
{
Phy_UpdateState(phyInstPtr);
} // PhyIntr_Handler
/****************************************************************************/
/**
* Handler of periodic 2 ms interrupt
*
* @param callBackRef is the linklayer instance pointer.
*
* @return None.
*
*****************************************************************************/
void PeriodicPoll_Handler(void *callBackRef)
{
int32_t Status;
Status = Linklayer_Proc(linkInstPtr);
if (Status != SUCCESS)
{
DBG_ERROR("Link layer runs failed, with error code: %" PRId32 "\n", Status);
_nop_();
}
} // PeriodicPoll_Handler
/*****************************************************************************/
/**
* @brief Handler of System Bus RX done interrupt.
*
* @param context
*
* @return None.
*
******************************************************************************/
void Systembus_RxIntrHandler(void *context)
{
int32_t Status;
Status = SystemBus_RxIntrHandler(sysbusDescPtr);
if (Status != SUCCESS)
{
DBG_ERROR("SystemBus_RxIntrHandler exit with error code %" PRId32 ",\n", Status);
}
}
/*****************************************************************************/
/**
* @brief Handler of System Bus TX done interrupt.
*
* @param context
*
* @return None.
*
******************************************************************************/
void Systembus_TxIntrHandler(void *context)
{
int32_t Status;
Status = SystemBus_TxIntrHandler(sysbusDescPtr);
if (Status != SUCCESS)
{
DBG_ERROR("SystemBus_TxIntrHandler exit with error code %" PRId32 ",\n", Status);
}
}
/*****************************************************************************/
/**
* @brief Handler of AppTimer interrupt.
*
* @param context
*
* @return None.
*
******************************************************************************/
void AppTimer_IntrHandler(void *context)
{
struct xil_timer_desc *xdesc;
xdesc = (struct xil_timer_desc *)(logTmPtr->extra);
#ifdef XPAR_XSCUTIMER_NUM_INSTANCES
if (XScuTimer_IsExpired((XScuTimer *)xdesc->instance))
{
// Refresh log
Phy_RefreshHwSate(phyInstPtr);
if (TimeCtrl_GetIntCnt(tmcInstPtr) - phyInstPtr->lastLogTime >= PHY_LOG_EXPIRE)
{
Phy_UpdateLogging(phyInstPtr);
}
XScuTimer_ClearInterruptStatus((XScuTimer *)xdesc->instance);
}
#elif defined(XPAR_XTMRCTR_NUM_INSTANCES)
if (XTmrCtr_IsExpired((XTmrCtr *)xdesc->instance, 0))
{
// Refresh log
Phy_RefreshHwSate(phyInstPtr);
if (TimeCtrl_GetIntCnt(tmcInstPtr) - phyInstPtr->lastLogTime >= PHY_LOG_EXPIRE)
{
Phy_UpdateLogging(phyInstPtr);
}
XTmrCtr_WriteReg(((XTmrCtr *)xdesc->instance)->BaseAddress, 0,
XTC_TCSR_OFFSET, XTC_CSR_INT_OCCURED_MASK);
}
#else
#error No timer implementation!
#endif
else
{
DBG_WARNING("UNEXPECTED CALL of AppTimer_IntrHandler\n");
}
}
/*****************************************************************************/
/**
* @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)
{
#ifdef HSJL_GE // Zynq MPSoC (Zynq UltraScale+)
metal_set_log_handler(MetalLogHandler);
metal_set_log_level(METAL_LOG_DEBUG);
#endif
int32_t Status;
DBG_PRINT("Application Version: %2d.%2d.%4d.\n", _APP_VER_MAIN, _APP_VER_MINOR, _APP_VER_PATCH);
/* System Monitor Initialize */
Status = SysMonitor_Init(&sysmonConfig);
if (Status == SUCCESS)
{
DBG_PRINT("System monitor Init SUCCESS! \n");
}
else
{
DBG_PRINT("System monitor Init FAILED! \n");
return Status;
}
/* Hardware Initialize */
Status = Hardware_Init();
if (Status == SUCCESS)
{
DBG_PRINT("Hardware Init SUCCESS! \n");
}
else
{
DBG_PRINT("Hardware Init FAILED! \n");
return Status;
}
/* Time controller Initialize */
Status = TimeCtrl_Init(&tmcInstPtr, &tmcConfig);
if (Status == SUCCESS)
{
DBG_PRINT("TmcCtrl Init SUCCESS! \n");
}
else
{
DBG_PRINT("TmcCtrl Init FAILED! \n");
return Status;
}
/* Physical Layer Initialize */
Status = Phy_Init(&phyInstPtr, &phyConfig);
if (Status == SUCCESS)
{
DBG_PRINT("Physical layer Init SUCCESS! \n");
}
else
{
DBG_PRINT("Physical layer FAILED! \n");
return Status;
}
/* Link Layer Initialize */
linkConfig.phyInstPtr = phyInstPtr;
linkConfig.tmcInstPtr = tmcInstPtr;
Status = Linklayer_Init(&linkInstPtr, &linkConfig);
if (Status == SUCCESS)
{
DBG_PRINT("LinkLayer Init SUCCESS! \n");
}
else
{
DBG_PRINT("Linklayer Init FAILED! \n");
return Status;
}
/* System Bus Initialize */
Status = SystemBus_Init(&sysbusDescPtr, &sysbusConfig);
if (Status != SUCCESS)
{
DBG_ERROR("Systembus init FAILED, with error code: %" PRId32 "\n", Status);
return Status;
}
/* System Monitor log timer Initialize */
Status = timer_init(&logTmPtr, &apptimer_init_param);
if (Status != SUCCESS)
{
DBG_ERROR("APP Timer init FAILED, with error code: %" PRId32 "\n", Status);
return Status;
}
/* interrupts Initialize */
Status = SetupInterruptSystem(intcDescPtr);
if (Status == SUCCESS)
{
DBG_INFO("Interrupt system setup SUCCESS!\n");
}
else
{
DBG_ERROR("Interrupt system setup FAILED, ErrorCode: %" PRId32 ".\n", Status);
return Status;
}
// Start System Monitor logging.
timer_start(logTmPtr);
DBG_PRINT("Physical started...\n");
Phy_Start(phyInstPtr);
Linklayer_Start(linkInstPtr);
while (true)
{
// System bus handler
if (SystemBus_IsReqPending(sysbusDescPtr))
{
Status = SystemBus_HandleCmd(sysbusDescPtr);
if (Status != SUCCESS)
{
DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
}
}
if (SystemBus_IsRespPending(sysbusDescPtr) && (!SystemBus_IsTxBusy(sysbusDescPtr)))
{
Status = SystemBus_MakeResp(sysbusDescPtr);
if (Status != SUCCESS)
{
DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
}
}
}
} // main