Files
df_datalink/df_datalink_sp/src/systembus/systembus.c
T
2024-06-25 10:59:54 +08:00

780 lines
21 KiB
C

/*****************************************************************************/
/**
* @file systembus.c
* @author FanHao ([email protected])
* @brief System bus protocol implementation file.
* @version 0.1
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup SystemBus
* @{
*/
/***************************** Include Files *********************************/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "systembus_uart.h"
#include "systembus.h"
#include "util.h"
#include "common.h"
#include "error.h"
#include "circ_queue.h"
#include "../system_monitor.h"
/**
* @addtogroup SystemBus_Protocol_Routine
* @{
*/
/************************** Constant Definitions *****************************/
/**
* @name SystemBus_MSG_Constants
* @{
*/
// Common Field
// -- Command word
#define WD_CMD 0x00
// -- Production type
#define WD_PRD 0x01
#define PRD_DL_K 0xDD
#define PRD_DL_S 0xEE
#define PRD_ALL 0xFF
// Self-Test
#define CMD_SELF_TEST 0xE1
// -- Request
// -- -- --
// -- Response
// -- -- Self-Test Result
#define ST_RSP_LEN 16
#define WD_ST_RET 0x02
#define ST_RET_OK 0xAA
#define ST_RET_ERROR 0x55
#define ST_RET_INFO_LEN 13
// -- -- Signal processor PS voltage
#define WD_SP_FPGA_VOLT 0x03
// -- -- Signal processor PS AUX voltage
#define WD_SP_CLK_STATE 0x04
// -- -- Signal processor DDR voltage
#define WD_SP_AD_LOCK_STATE 0x05
// -- -- Signal processor PL voltage
#define WD_SP_AD_TEMP_0 0x06
// -- -- Signal processor PL AUX voltage
#define WD_SP_AD_TEMP_1 0x07
// -- -- Signal processor Bram voltage
#define WD_SP_FPGA_TEMP 0x08
// -- -- Signal processor antenna voltage status
#define WD_ANT_VOLT 0x09
// -- -- Signal processor antenna RF temperature
#define WD_ANT_RF_TEMP 0x0A
// -- -- Signal processor antenna PLL lock status
#define WD_ANT_RF_PLL 0x0B
// -- -- Signal processor antenna MGC
#define WD_ANT_MGC_0 0x0C
#define WD_ANT_MGC_1 0x0D
// -- -- Reserved
#define WD_ANT_RESERVE 0x0E
// Data Send Test Command
#define CMD_DATA_TEST_A 0xE2
// -- Request
#define DATA_TEST_REQ_A_LEN 68
// -- -- 68 byte payload
// -- Response
#define DATA_TEST_RSP_A_LEN 68
// -- -- 68 byte payload
// Data Send Test Command
#define CMD_DATA_TEST_B 0xF2
// -- Request
#define DATA_TEST_REQ_B_LEN 170
// -- -- 170 byte payload
// -- Response
#define DATA_TEST_RSP_B_LEN 170
// -- -- 170 byte payload
// Config load
#define CMD_CONFIG 0xE3
// -- Request
#define WD_EN_CMD 0x02
#define EN_CMD_ON_HIGH_POWER 0x66
#define EN_CMD_ON_LOW_POWER 0x77
#define EN_CMD_SILENT 0x88
#define WD_MODE_CMD 0x03
#define MODE_CMD_HEAD 0x11
#define MODE_CMD_MEMBER 0x00
// -- Response
// -- -- none response
// System info update
#define CMD_SYS_INFO 0x33
#define SYS_INFO_OFFSET 2
// -- Request
// -- -- 54 byte system info
// -- Response
// -- -- none response
// Data Send Test Command
#define CMD_FLJ_SEND 0xE4
#define FLJ_DATA_OFFSET 2
// -- Request
// -- -- 78 byte payload
// -- Response
// -- -- none response
// Data Send Test Command
#define CMD_LJ_SEND 0xF4
#define LJ_DATA_OFFSET 2
// -- Request
// -- -- 156 byte payload
// -- Response
// -- -- none response
// FLJ Poll
#define CMD_FLJ_POLL 0xE5
// -- Request
#define WD_FLJ_POLL 0x02
#define FLJ_POLL_CODE 0x77
// -- Response
#define FLJ_POLL_RESP_LEN 170
// -- -- received 170 byte payload
// LJ Poll
#define CMD_LJ_POLL 0xF5
// -- Request
#define WD_LJ_POLL 0x02
#define LJ_POLL_CODE 0x77
// -- Response
#define LJ_POLL_RESP_LEN 68
// -- -- received 68 byte payload
// Remote Test FLJ
#define CMD_FLJ_RM_TEST 0xE6
// -- Request
#define WD_FLJ_RM_TEST 0x02
#define FLJ_RM_TEST_CODE 0x99
// -- Response
#define WD_FLJ_TIME_STAMP 0x02
#define WD_FLJ_TIME_STAMP_LEN 8
#define WD_FLJ_SYSBUS_LOG 0x0A
#define WD_FLJ_SYSBUS_LOG_LEN 14
#define WD_FLJ_LINK_LOG 0x18
#define WD_FLJ_LINK_LOG_LEN 64
#define WD_FLJ_PHY_LOG 0x58
#define WD_FLJ_PHY_LOG_LEN 57
#define WD_FLJ_HARDWARE_ST 0x91
#define WD_FLJ_HARDWARE_ST_LEN 13
#define FLJ_RM_TEST_RESP_LEN 158
// Remote Test LJ
#define CMD_LJ_RM_TEST 0xF6
// -- Request
#define WD_LJ_RM_TEST 0x02
#define LJ_RM_TEST_CODE 0x99
// -- Response
#define WD_LJ_TIME_STAMP 0x02
#define WD_LJ_TIME_STAMP_LEN 8
#define WD_LJ_SYSBUS_LOG 0x0A
#define WD_LJ_SYSBUS_LOG_LEN 14
#define WD_LJ_LINK_LOG 0x18
#define WD_LJ_LINK_LOG_LEN 64
#define WD_LJ_PHY_LOG 0x58
#define WD_LJ_PHY_LOG_LEN 57
#define WD_LJ_HARDWARE_ST 0x91
#define WD_LJ_HARDWARE_ST_LEN 13
#define LJ_RM_TEST_RESP_LEN 158
// My Production Type
#define MY_PRD_ID PRD_DL_K
/** @} SystemBus_MSG_Constants*/
/************************** Function Prototypes ******************************/
static int32_t SystemBus_GenSelfTestRsp(SYSBUS *instPtr);
static int32_t SystemBus_SystemConfig(SYSBUS *instPtr, uint8_t *msg);
static int32_t SystemBus_Echo(SYSBUS *instPtr, SYSBUS_UART_FRAME *frame);
static int32_t SystemBus_GenPollRsp(SYSBUS *instPtr, uint8_t *msg);
static int32_t SystemBus_GenRemoteTestRsp(SYSBUS *instPtr, uint8_t *msg);
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
// TODO: better approach?
#include "../networking/link_layer/link_layer.h"
#include "../networking/phy_layer/phy_layer.h"
extern L2_INST *linkInstPtr;
extern L2_CONFIG linkConfig;
inline bool SystemBus_IsReqPending(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
return (!isCircQueueEmpty(instPtr->rxQueue));
}
inline bool SystemBus_IsRsqPending(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
return (!isCircQueueEmpty(instPtr->txQueue));
}
inline bool SystemBus_IsTxBusy(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
return (!instPtr->isTxDone);
}
inline bool SystemBus_IsRxBusy(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
return SysbusUart_IsRxBusy(instPtr->uartInst);
}
/**
* @brief Generate System Bus SelfTest response.
*/
static int32_t SystemBus_GenSelfTestRsp(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
SYSBUS_UART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_UART_FRAME));
if (sysbusRsp == NULL)
{
DBG_ERROR("Failed to allocate memory for SELF TEST Response!\n");
return ENOMEM;
}
HWSTATE *hwStatsPtr = &(instPtr->hwState);
sysbusRsp->len = ST_RSP_LEN;
memset(sysbusRsp->data, 0x00, ST_RSP_LEN);
sysbusRsp->data[WD_CMD] = CMD_SELF_TEST;
sysbusRsp->data[WD_PRD] = MY_PRD_ID;
SysMonitor_GetHardwareStatus(hwStatsPtr);
if (L2_isStarted(linkInstPtr))
{
sysbusRsp->data[WD_ST_RET] = (hwStatsPtr->isSpOk && hwStatsPtr->isAntOk) ? ST_RET_OK : ST_RET_ERROR;
}
else
{
sysbusRsp->data[WD_ST_RET] = (hwStatsPtr->isSpOk) ? ST_RET_OK : ST_RET_ERROR;
}
// apply status and omit 2 bytes of overhead.
memcpy(sysbusRsp->data + WD_SP_FPGA_VOLT, &(hwStatsPtr->spFpgaVolt), ST_RET_INFO_LEN);
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
{
free(sysbusRsp);
DBG_ERROR("SystemBus::TX Queue overflowed!\n");
return EQUEUE;
}
return SUCCESS;
}
/**
* @brief Apply system configuration
*/
static int32_t SystemBus_SystemConfig(SYSBUS *instPtr, uint8_t *msg)
{
ASSERT(instPtr != NULL);
ASSERT(msg != NULL);
PHY_INST *phyRef = linkInstPtr->config.phyInstPtr;
TMC_INST *tmcRef = linkInstPtr->config.tmcInstPtr;
bool reconfig = false;
if (msg[WD_MODE_CMD] == MODE_CMD_HEAD)
{
// head node config
reconfig = (L2_NODE_HEAD != L2_GetNodeType(linkInstPtr));
linkConfig.myType = L2_NODE_HEAD;
linkConfig.myId = 1;
}
else if (msg[WD_MODE_CMD] == MODE_CMD_MEMBER)
{
// member node config
reconfig = (L2_NODE_MEMBER != L2_GetNodeType(linkInstPtr));
linkConfig.myType = L2_NODE_MEMBER;
linkConfig.myId = 2;
}
else
{
// Ignore current command
DBG_ERROR("Unexpected config command 0x%02X:0x%02X",
WD_MODE_CMD, msg[WD_MODE_CMD]);
return EPARAM;
}
if (msg[WD_EN_CMD] == EN_CMD_ON_HIGH_POWER)
{
// full power config
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_FULL);
if (reconfig || !L2_isStarted(linkInstPtr))
{
Linklayer_Reconfig(linkInstPtr, &linkConfig);
}
Linklayer_Start(linkInstPtr);
}
else if (msg[WD_EN_CMD] == EN_CMD_ON_LOW_POWER)
{
// low power config
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_LOW);
if (reconfig || !L2_isStarted(linkInstPtr))
{
Linklayer_Reconfig(linkInstPtr, &linkConfig);
}
Linklayer_Start(linkInstPtr);
}
else if (msg[WD_EN_CMD] == EN_CMD_SILENT)
{
// silence config
// TODO: better approach?
Linklayer_Halt(linkInstPtr);
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_STANDBY);
TIME_WORD pullTime = {0, 0};
pullTime.int_part = TimeCtrl_GetIntCnt(tmcRef) + 1;
if (Phy_SetTimeWord(phyRef, &pullTime, PHY_TIME_WORD_POLL) != SUCCESS)
{
DBG_ERROR("Physical set pull time failed.\n");
}
Phy_SetupNextSlot(phyRef, PHY_TOR_RX, L1_10KBPS_10MS_FRAME, NULL);
}
else
{
// Ignore current command
DBG_ERROR("Unexpected config command 0x%02X:0x%02X",
WD_EN_CMD, msg[WD_EN_CMD]);
return EIGNORE;
}
instPtr->sysbusLog.lastConfig[0] = msg[WD_MODE_CMD];
instPtr->sysbusLog.lastConfig[1] = msg[WD_EN_CMD];
return SUCCESS;
}
/**
* @brief Echo System Bus frame
*/
static int32_t SystemBus_Echo(SYSBUS *instPtr, SYSBUS_UART_FRAME *frame)
{
ASSERT(instPtr != NULL);
ASSERT(frame != NULL);
SYSBUS_UART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_UART_FRAME));
if (sysbusRsp == NULL)
{
DBG_ERROR("Failed to allocate memory for DATA TEST A Response!\n");
return ENOMEM;
}
sysbusRsp->len = frame->len;
memcpy(sysbusRsp->data, frame->data, sysbusRsp->len);
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
{
free(sysbusRsp);
DBG_ERROR("SystemBus::TX Queue overflowed!\n");
return EQUEUE;
}
return SUCCESS;
}
/**
* @brief Generate System Bus poll call command response
*/
static int32_t SystemBus_GenPollRsp(SYSBUS *instPtr, uint8_t *msg)
{
ASSERT(instPtr != NULL);
ASSERT(msg != NULL);
size_t dataLen;
uint8_t *payload;
SYSBUS_UART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_UART_FRAME));
if (sysbusRsp == NULL)
{
DBG_ERROR("Failed to allocate memory for FLJ POLL Response!\n");
return ENOMEM;
}
if (msg[WD_CMD] == CMD_FLJ_POLL)
{
sysbusRsp->len = FLJ_POLL_RESP_LEN;
sysbusRsp->data[WD_CMD] = CMD_FLJ_POLL;
sysbusRsp->data[WD_PRD] = MY_PRD_ID;
dataLen = PAYLOAD_LEN_FLJ_RX;
payload = sysbusRsp->data + FLJ_DATA_OFFSET;
}
else if (msg[WD_CMD] == CMD_LJ_POLL)
{
sysbusRsp->len = LJ_POLL_RESP_LEN;
sysbusRsp->data[WD_CMD] = CMD_LJ_POLL;
sysbusRsp->data[WD_PRD] = MY_PRD_ID;
dataLen = PAYLOAD_LEN_LJ_RX;
payload = sysbusRsp->data + LJ_DATA_OFFSET;
}
else
{
DBG_ERROR("Unexpected command 0x%02X.\n", msg[WD_CMD]);
free(sysbusRsp);
return EUNEXP;
}
uint32_t dataId;
SysMonitor_GetRecvPayload(payload, &dataId, dataLen); // omit control info
if (dataId == DATA_ID_NONE)
{
free(sysbusRsp);
DBG_WARNING("SystemBus::no RX data!\n");
return SUCCESS;
}
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
{
free(sysbusRsp);
DBG_WARNING("SystemBus::TX Queue overflowed!\n");
return EQUEUE;
}
instPtr->sysbusLog.pollCnt++;
return SUCCESS;
}
/**
* @brief Generate System Bus remote test command response
*/
static int32_t SystemBus_GenRemoteTestRsp(SYSBUS *instPtr, uint8_t *msg)
{
ASSERT(instPtr != NULL);
ASSERT(msg != NULL);
SYSBUS_UART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_UART_FRAME));
if (sysbusRsp == NULL)
{
DBG_ERROR("Failed to allocate memory for LJ REMOTE TEST Response!\n");
return ENOMEM;
}
TIME_WORD tmWord;
uint64_t time;
TimeCtrl_GetCurrentTime(linkInstPtr->config.tmcInstPtr, &tmWord);
time = (uint64_t)tmWord.int_part * TIME_FRAC_MAX + tmWord.frac_part;
if (msg[WD_CMD] == CMD_FLJ_RM_TEST)
{
sysbusRsp->len = FLJ_RM_TEST_RESP_LEN;
memset(sysbusRsp->data, 0x00, FLJ_RM_TEST_RESP_LEN);
sysbusRsp->data[WD_CMD] = CMD_FLJ_RM_TEST;
sysbusRsp->data[WD_PRD] = MY_PRD_ID;
memcpy(sysbusRsp->data + WD_FLJ_TIME_STAMP, &time, WD_FLJ_TIME_STAMP_LEN);
SysMonitor_GetLinklayerLog(&(instPtr->linkLog));
SysMonitor_GetPhysicalLayerLog(&(instPtr->phyLog));
SysMonitor_GetHardwareStatus(&(instPtr->hwState));
memcpy(sysbusRsp->data + WD_FLJ_SYSBUS_LOG, &(instPtr->sysbusLog), WD_FLJ_SYSBUS_LOG_LEN);
memcpy(sysbusRsp->data + WD_FLJ_LINK_LOG, &(instPtr->linkLog), WD_FLJ_LINK_LOG_LEN);
memcpy(sysbusRsp->data + WD_FLJ_PHY_LOG, &(instPtr->phyLog), WD_FLJ_PHY_LOG_LEN);
memcpy(sysbusRsp->data + WD_FLJ_HARDWARE_ST, &(instPtr->hwState.spFpgaVolt), WD_FLJ_HARDWARE_ST_LEN);
}
else if (msg[WD_CMD] == CMD_LJ_RM_TEST)
{
sysbusRsp->len = LJ_RM_TEST_RESP_LEN;
sysbusRsp->data[WD_CMD] = CMD_LJ_RM_TEST;
sysbusRsp->data[WD_PRD] = MY_PRD_ID;
memcpy(sysbusRsp->data + WD_LJ_TIME_STAMP, &time, WD_LJ_TIME_STAMP_LEN);
SysMonitor_GetLinklayerLog(&(instPtr->linkLog));
SysMonitor_GetPhysicalLayerLog(&(instPtr->phyLog));
SysMonitor_GetHardwareStatus(&(instPtr->hwState));
memcpy(sysbusRsp->data + WD_LJ_SYSBUS_LOG, &(instPtr->sysbusLog), WD_LJ_SYSBUS_LOG_LEN);
memcpy(sysbusRsp->data + WD_LJ_LINK_LOG, &(instPtr->linkLog), WD_LJ_LINK_LOG_LEN);
memcpy(sysbusRsp->data + WD_LJ_PHY_LOG, &(instPtr->phyLog), WD_LJ_PHY_LOG_LEN);
memcpy(sysbusRsp->data + WD_LJ_HARDWARE_ST, &(instPtr->hwState.spFpgaVolt), WD_LJ_HARDWARE_ST_LEN);
}
else
{
DBG_ERROR("Unexpected command 0x%02X.\n", msg[WD_CMD]);
free(sysbusRsp);
return EUNEXP;
}
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
{
free(sysbusRsp);
DBG_WARNING("SystemBus::TX Queue overflowed!\n");
return EQUEUE;
}
instPtr->sysbusLog.remoteCnt++;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief A handler function. This handler evaluate the message from system
* bus receive queue, and make appropriate response.
*
* @param instPtr A pointer to System Bus instance.
*
* @return None
*
******************************************************************************/
int32_t SystemBus_HandleCmd(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
int32_t Status;
SYSBUS_UART_FRAME *sysbusReq;
uint8_t *msg;
if (CircQueuePop(instPtr->rxQueue, (void **)(&sysbusReq)) == false)
{
DBG_WARNING("SystemBus::Nothing to be handled.\n");
return EIGNORE;
}
msg = sysbusReq->data;
if (msg[WD_PRD] != MY_PRD_ID && msg[WD_PRD] != PRD_ALL)
{
DBG_WARNING("SystemBus::Production code mismatch!\n");
return EIGNORE;
}
switch (msg[WD_CMD])
{
case CMD_SELF_TEST:
{
Status = SystemBus_GenSelfTestRsp(instPtr);
break;
}
case CMD_DATA_TEST_A:
case CMD_DATA_TEST_B:
{
Status = SystemBus_Echo(instPtr, sysbusReq);
break;
}
case CMD_CONFIG:
{
Status = SystemBus_SystemConfig(instPtr, msg);
break;
}
case CMD_SYS_INFO:
{
SysMonitor_UpdateSysinfo((SYSINFO *)(msg + SYS_INFO_OFFSET));
Status = SUCCESS;
break;
}
case CMD_FLJ_SEND:
{
SysMonitor_UpdateSendPayload(msg + FLJ_DATA_OFFSET, PAYLOAD_LEN_FLJ_TX); // omit control info
instPtr->sysbusLog.svcCnt++;
Status = SUCCESS;
break;
}
case CMD_LJ_SEND:
{
SysMonitor_UpdateSendPayload(msg + LJ_DATA_OFFSET, PAYLOAD_LEN_LJ_TX); // omit control info
instPtr->sysbusLog.svcCnt++;
Status = SUCCESS;
break;
}
case CMD_FLJ_POLL:
{
if (msg[WD_FLJ_POLL] != FLJ_POLL_CODE)
{
DBG_ERROR("SystemBus::Invalid roll call code!\n");
Status = EIGNORE;
break;
}
Status = SystemBus_GenPollRsp(instPtr, msg);
break;
}
case CMD_LJ_POLL:
{
if (msg[WD_LJ_POLL] != LJ_POLL_CODE)
{
DBG_WARNING("SystemBus::Invalid roll call code!\n");
Status = EIGNORE;
break;
}
Status = SystemBus_GenPollRsp(instPtr, msg);
break;
}
case CMD_FLJ_RM_TEST:
{
if (msg[WD_FLJ_RM_TEST] != FLJ_RM_TEST_CODE)
{
DBG_WARNING("SystemBus::Invalid remote test code!\n");
Status = EIGNORE;
break;
}
Status = SystemBus_GenRemoteTestRsp(instPtr, msg);
break;
}
case CMD_LJ_RM_TEST:
{
if (msg[WD_LJ_RM_TEST] != LJ_RM_TEST_CODE)
{
DBG_WARNING("SystemBus::Invalid remote test code!\n");
Status = EIGNORE;
break;
}
Status = SystemBus_GenRemoteTestRsp(instPtr, msg);
break;
}
default:
{
DBG_ERROR("SystemBus::Unknown command code!\n");
Status = FAILURE;
break;
}
}
free(sysbusReq);
return Status;
}
/*****************************************************************************/
/**
* @brief This function send a repose frame from system bus tx queue.
*
* @param instPtr A pointer to System Bus instance.
*
* @return None
*
******************************************************************************/
int32_t SystemBus_MakeResp(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
int32_t Status;
SYSBUS_UART_FRAME *sysbusRsp;
if (CircQueuePop(instPtr->txQueue, (void **)(&sysbusRsp)) == false)
{
DBG_WARNING("SystemBus::Nothing to be sent.\n");
return EIGNORE;
}
instPtr->isTxDone = false; // A transmission procedure is started.
Status = SysbusUart_Send(instPtr->uartInst, sysbusRsp);
free(sysbusRsp);
return Status;
}
/** @} */
/*****************************************************************************/
/**
* @brief Initialize System Bus instance.
*
* @param InstPtr A double pointer to System Bus instance.
* @param config A pointer to System Bus configurations.
*
* @return Error code.
*
******************************************************************************/
int32_t SystemBus_Init(SYSBUS **instPtr, SYSBUS_CONFIG *config)
{
ASSERT(instPtr != NULL);
ASSERT(config != NULL);
SYSBUS_UART_CONFIG uartConfig;
int32_t Status;
(*instPtr) = malloc(sizeof(SYSBUS));
if ((*instPtr) == NULL)
{
return ENOMEM;
}
(*instPtr)->rxQueue = NULL;
(*instPtr)->txQueue = NULL;
(*instPtr)->uartInst = NULL;
memcpy(&((*instPtr)->config), config, sizeof(SYSBUS_CONFIG));
memset(&((*instPtr)->sysbusLog), 0x00, sizeof(SYSBUSLOG));
memset(&((*instPtr)->linkLog), 0x00, sizeof(LINKLOG));
memset(&((*instPtr)->phyLog), 0x00, sizeof(PHYLOG));
memset(&((*instPtr)->hwState), 0x00, sizeof(HWSTATE));
uartConfig.baseAddr = config->baseAddr;
Status = SysbusUart_Init(&((*instPtr)->uartInst), &uartConfig);
if (Status != SUCCESS)
{
SystemBus_Destroy(*instPtr);
return ENOMEM;
}
if (CircQueueCreate(&((*instPtr)->txQueue), (*instPtr)->config.txQueueMax) == false)
{
SystemBus_Destroy(*instPtr);
return ENOMEM;
}
if (CircQueueCreate(&((*instPtr)->rxQueue), (*instPtr)->config.rxQueueMax) == false)
{
SystemBus_Destroy(*instPtr);
return ENOMEM;
}
(*instPtr)->isRxDone = false; // nothing received.
(*instPtr)->isTxDone = true; // nothing to be sent.
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Destroy System Bus instance.
*
* @param InstPtr A pointer to System Bus instance.
*
* @return None.
*
******************************************************************************/
void SystemBus_Destroy(SYSBUS *instPtr)
{
if (instPtr == NULL)
{
return;
}
free(instPtr->uartInst);
free(instPtr->txQueue);
free(instPtr->rxQueue);
free(instPtr);
}
/*****************************************************************************/
/**
* @brief This function handles the systembus tx irq events.
*
* @param instPtr A pointer to System Bus instance.
*
* @return None
*
******************************************************************************/
int32_t SystemBus_TxIntrHandler(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
// nothing special...
instPtr->isTxDone = true; // A transmission procedure finished.
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief This function handles the systembus rx irq events.
*
* @param instPtr A pointer to System Bus instance.
*
* @return None
*
******************************************************************************/
int32_t SystemBus_RxIntrHandler(SYSBUS *instPtr)
{
ASSERT(instPtr != NULL);
instPtr->isRxDone = true; // whether reception successes or not, receiving procedure ended.
int32_t Status;
SYSBUS_UART_FRAME *sysbusReq = malloc(sizeof(SYSBUS_UART_FRAME));
if (sysbusReq == NULL)
{
return ENOMEM;
}
Status = SysbusUart_Recv(instPtr->uartInst, sysbusReq);
if (Status != SUCCESS)
{
free(sysbusReq);
return Status;
}
if (CircQueuePush(instPtr->rxQueue, (void *)sysbusReq) == false)
{
DBG_ERROR("SystemBus::RX Queue overflowed!\n");
free(sysbusReq);
return EQUEUE;
}
instPtr->isRxDone = false; // another reception is undergoing.
return SUCCESS;
}
/** @} SystemBus*/