Files
hj_datalink/src/systembus/systembus_uart.c
T

221 lines
5.1 KiB
C

/*****************************************************************************/
/**
* @file systembus_uart.h
* @author FanHao ([email protected])
* @brief System bus uart driver 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
* @{
*/
/**
* @addtogroup SystemBus_UART
* @{
*/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "systembus_uart.h"
#include "common.h"
/**
* @name SystemBus_UART_Driver_Constants
* @{
*/
// Control and status register
#define MODULE_VERSION 0x00000000U
#define UART_STATUS 0x0000004U
#define UART_SEND_CMD 0x00000008U
#define UART_RECV_CNT 0x0000000CU
// Status code
#define UART_STATUS_TX_BUSY 0x00010000
#define UART_STATUS_RX_BUSY 0x01000000
// Data buffer register
#define UART_TXBUFF_OFFSET 1024
#define UART_TXBUFF_MAX 1024
#define UART_RXBUFF_OFFSET 2048
#define UART_RXBUFF_MAX 1024
#if (UART_TXBUFF_MAX < UART_FRM_MAX || UART_RXBUFF_MAX < UART_FRM_MAX)
#error "UART_FRM_MAX exceeds the maximum value."
#endif
// Frame Data offsets
#define FRAME_HEAD_LOW 0x5A
#define FRAME_HEAD_HIGH 0x54
#define FRAME_TAIL_LOW 0x5A
#define FRAME_TAIL_HIGH 0xFE
#define FRAME_HEAD_LEN 2
#define FRAME_TAIL_LEN 2
#define FRAME_DUMMY_LEN 1 // Dummy
#define FRAME_CHECK_LEN 1 // CheckSum
#define FRAME_INFO_LEN 3 // CheckSum, Dummy and DataLen
#define FRAME_OVERHEAD_LEN 7 // CheckSum, Dummy and DataLen
/** @} SystemBus_UART_Driver_Constants*/
int SysbusUart_Init(SYSBUS_UART **instPtr, SYSBUS_UART_CONFIG *config)
{
ASSERT(instPtr != NULL);
ASSERT(config != NULL);
(*instPtr) = malloc(sizeof(SYSBUS_UART));
if ((*instPtr) == NULL)
{
return FAILURE;
}
(*instPtr)->config.baseAddr = config->baseAddr;
return SUCCESS;
}
int SysbusUart_Send(SYSBUS_UART *instPtr, SYSBUS_UART_FRAME *frame)
{
ASSERT(instPtr != NULL);
ASSERT(frame != NULL);
uint8_t checkSum;
uint16_t dLen, sendLen;
uint8_t *sendBuff;
if (frame->len > UART_TXBUFF_MAX || frame->len == 0)
{
return FAILURE;
}
sendBuff = malloc(sizeof(uint8_t) * UART_TXBUFF_MAX);
if (sendBuff == NULL)
{
return FAILURE;
}
sendBuff[0] = FRAME_HEAD_LOW;
sendBuff[1] = FRAME_HEAD_HIGH;
dLen = 0;
checkSum = 0;
for (int i = 0; i < frame->len - 1; i++)
{
if (frame->data[i] == FRAME_TAIL_LOW && frame->data[i + 1] == FRAME_TAIL_HIGH)
{
sendBuff[FRAME_HEAD_LEN + dLen] = 0x00;
dLen++;
}
sendBuff[FRAME_HEAD_LEN + dLen] = frame->data[i];
checkSum += sendBuff[FRAME_HEAD_LEN + dLen];
dLen++;
}
// Last Byte
sendBuff[FRAME_HEAD_LEN + dLen] = frame->data[frame->len - 1];
checkSum += sendBuff[FRAME_HEAD_LEN + dLen];
dLen++;
// Dummy Byte
sendBuff[FRAME_HEAD_LEN + dLen] = 0x00;
// Check Sum
sendBuff[FRAME_HEAD_LEN + dLen + 1] = checkSum;
// Data Len
sendBuff[FRAME_HEAD_LEN + dLen + 2] = dLen;
// Frame Tail
sendBuff[FRAME_HEAD_LEN + dLen + 3] = FRAME_TAIL_LOW;
sendBuff[FRAME_HEAD_LEN + dLen + 4] = FRAME_TAIL_HIGH;
sendLen = dLen + FRAME_OVERHEAD_LEN;
if (sendLen > UART_TXBUFF_MAX)
{
free(sendBuff);
return FAILURE;
}
memcpy((void *)(instPtr->config.baseAddr + UART_TXBUFF_OFFSET), sendBuff,
NORMALIZE_SIZE((sendLen + sizeof(uint32_t) - 1) / sizeof(uint32_t) * sizeof(uint32_t)));
free(sendBuff);
// Start Sending
SYSTEMBUS_UART_mWriteReg(instPtr->config.baseAddr, UART_SEND_CMD, sendLen);
return SUCCESS;
}
int SysbusUart_Recv(SYSBUS_UART *instPtr, SYSBUS_UART_FRAME *frame)
{
ASSERT(instPtr != NULL);
ASSERT(frame != NULL);
uint16_t dLen, dWLen, plLen;
uint8_t checkSum, checkSumCal;
uint8_t *plBuff, *dBuff;
dLen = SYSTEMBUS_UART_mReadReg(instPtr->config.baseAddr, UART_RECV_CNT);
if (dLen == 0 || dLen > UART_TXBUFF_MAX)
{
return EPARAM;
}
dWLen = (dLen + FRAME_HEAD_LEN + FRAME_INFO_LEN - 1) / 4 + 1;
dBuff = malloc(sizeof(uint32_t) * dWLen);
if (dBuff == NULL)
{
return ENOMEM;
}
memcpy(dBuff, (void *)(instPtr->config.baseAddr + UART_RXBUFF_OFFSET),
NORMALIZE_SIZE(sizeof(uint32_t) * dWLen));
plBuff = dBuff + FRAME_HEAD_LEN;
checkSumCal = 0;
checkSum = plBuff[dLen + FRAME_DUMMY_LEN];
plLen = 0;
for (int i = 0; i < dLen; i++)
{
if (plBuff[i + 1] == FRAME_TAIL_LOW && plBuff[i + 2] == FRAME_TAIL_HIGH)
{
continue;
}
checkSumCal += plBuff[i];
frame->data[plLen] = plBuff[i];
plLen++;
}
free(dBuff);
frame->len = plLen;
frame->checkSum = checkSumCal;
if (checkSumCal != checkSum)
{
frame->isValid = false;
return FAILURE;
}
frame->isValid = true;
return SUCCESS;
}
bool SysbusUart_IsRxBusy(SYSBUS_UART *instPtr)
{
ASSERT(instPtr != NULL);
uint32_t Status;
Status = SYSTEMBUS_UART_mReadReg(instPtr->config.baseAddr, UART_STATUS);
if (Status & UART_STATUS_RX_BUSY)
{
return true;
}
else
{
return false;
}
}
bool SysbusUart_IsTxBusy(SYSBUS_UART *instPtr)
{
ASSERT(instPtr != NULL);
uint32_t Status;
Status = SYSTEMBUS_UART_mReadReg(instPtr->config.baseAddr, UART_STATUS);
if (Status & UART_STATUS_TX_BUSY)
{
return true;
}
else
{
return false;
}
}
/** @} SystemBus_UART*/
/** @} SystemBus*/