/*****************************************************************************/ /** * @file systembus_uart.h * @author FanHao (hao_fan_bit_ee@163.com) * @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 #include #include #include #include "systembus_uart.h" #include "common.h" /** * @name SystemBus_UART_Driver_Constants * @{ */ // Control and status register #define MODULE_VERSION 0 #define UART_STATUS 4 #define UART_SEND_CMD 8 #define UART_RECV_CNT 12 // 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 // 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*/ /*****************************************************************************/ /** * @brief Instance initial * * @param instPtr A pointer to frame uart instance structure. * @param config Base address of frame uart, refer to "xparameters.h" * * @return None. * ******************************************************************************/ 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; } /*****************************************************************************/ /** * @brief Send a system bus frame. * * @param instPtr A pointer to SYSBUS_UART instance structure. * @param buff A pointer to send data buffer * @param dLen A integer indicate the send data buffer length in byte. * * @return * ******************************************************************************/ int SysbusUart_Send(SYSBUS_UART *instPtr, SYSBUS_UART_FRAME *frame) { ASSERT(instPtr != NULL); ASSERT(frame != NULL); uint8_t dLen, checkSum; uint8_t 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, (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; } /*****************************************************************************/ /** * @brief Get last system bus frame. * * @param instPtr A pointer to SYSBUS_UART instance structure. * @param buff A pointer to receive data buffer. * * @return * ******************************************************************************/ int SysbusUart_Recv(SYSBUS_UART *instPtr, SYSBUS_UART_FRAME *frame) { ASSERT(instPtr != NULL); ASSERT(frame != NULL); uint8_t dLen, dWLen, plLen, 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), 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; } /*****************************************************************************/ /** * @brief Get rx channel status. * * @param instPtr A pointer to SYSBUS_UART instance structure. * * @return true - SYSBUS_UART rx channel is busy. * false - SYSBUS_UART rx channel is idle. * ******************************************************************************/ 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; } } /*****************************************************************************/ /** * @brief Get tx channel status. * * @param instPtr A pointer to SYSBUS_UART instance structure. * * @return true - SYSBUS_UART tx channel is busy. * false - SYSBUS_UART tx channel is idle. * ******************************************************************************/ 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*/