218 lines
4.3 KiB
C
218 lines
4.3 KiB
C
#include "usart.h"
|
|
|
|
// Defines
|
|
#define DEL 0x7F
|
|
#define BACKSPACE 0x08
|
|
#define CR 0x0D
|
|
#define LF 0x0A
|
|
|
|
// Global variables
|
|
ringbuffer_t g_rx_buf = { 0 };
|
|
ringbuffer_t g_tx_buf = { 0 };
|
|
volatile uint8_t g_tx_sending = 0;
|
|
uint8_t g_echo_serial = 1;
|
|
|
|
uint8_t g_rx_buffer_data[RXBUF_SIZE];
|
|
uint8_t g_tx_buffer_data[TXBUF_SIZE];
|
|
|
|
|
|
void init_uart(void)
|
|
{
|
|
MX_USART1_UART_Init();
|
|
|
|
// Initialise the RX and TX buffers
|
|
ring_buf_init(&g_rx_buf, g_rx_buffer_data, RXBUF_SIZE);
|
|
ring_buf_init(&g_tx_buf, g_tx_buffer_data, TXBUF_SIZE);
|
|
|
|
// Clear Overrun flag, in case characters have already been sent to USART
|
|
USART1->ICR = USART_ICR_ORECF;
|
|
|
|
// Enable RXNE interrupt
|
|
USART1->CR1 |= USART_CR1_RXNEIE;
|
|
}
|
|
|
|
void ring_buf_init(ringbuffer_t *buf, uint8_t *bufData, uint16_t size)
|
|
{
|
|
buf->buf = bufData;
|
|
buf->head = 0;
|
|
buf->tail = 0;
|
|
buf->count = 0;
|
|
buf->size = size;
|
|
buf->mask = size - 1;
|
|
}
|
|
|
|
void ring_buf_wait_full(ringbuffer_t *buf)
|
|
{
|
|
while (is_ring_buf_full(buf))
|
|
{
|
|
if (!g_tx_sending)
|
|
{
|
|
g_tx_sending = 1;
|
|
USART1->CR1 |= USART_CR1_TXEIE; // Enable the TX empty interrupt
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
uint8_t ring_buf_get(ringbuffer_t *buf)
|
|
{
|
|
if (!buf->buf)
|
|
return 0;
|
|
|
|
uint8_t ret = buf->buf[buf->tail];
|
|
buf->tail = (buf->tail + 1) & buf->mask;
|
|
buf->count--;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void ring_buf_put(ringbuffer_t *buf, const uint8_t c)
|
|
{
|
|
if (!buf->buf)
|
|
return;
|
|
|
|
buf->buf[buf->head] = c;
|
|
// increment the head index
|
|
buf->head = (buf->head + 1) & buf->mask;
|
|
buf->count++;
|
|
}
|
|
|
|
inline uint8_t is_ring_buf_full(ringbuffer_t *buf)
|
|
{
|
|
return ((buf->head - buf->tail) & buf->mask) == buf->mask;
|
|
}
|
|
|
|
inline uint8_t is_ring_buf_empty(ringbuffer_t *buf)
|
|
{
|
|
return (buf->tail == buf->head);
|
|
}
|
|
|
|
int __io_putchar(int ch)
|
|
{
|
|
if (ch == '\n')
|
|
{
|
|
ring_buf_wait_full(&g_tx_buf);
|
|
ring_buf_put(&g_tx_buf, '\r');
|
|
}
|
|
|
|
ring_buf_wait_full(&g_tx_buf);
|
|
ring_buf_put(&g_tx_buf, ch);
|
|
|
|
if (!g_tx_sending)
|
|
{
|
|
g_tx_sending = 1;
|
|
USART1->CR1 |= USART_CR1_TXEIE; // Enable the TX empty interrupt
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
int _write(int file, char *ptr, int len)
|
|
{
|
|
for (int i= 0; i < len; i++)
|
|
__io_putchar( *ptr++ );
|
|
|
|
return len;
|
|
}
|
|
|
|
char get_line(char *lineBuf, uint16_t maxChars)
|
|
{
|
|
static int count = 0;
|
|
char res = 0;
|
|
|
|
if (g_rx_buf.count == 0)
|
|
return 0;
|
|
|
|
if (count < maxChars - 1)
|
|
{
|
|
uint8_t c = ring_buf_get(&g_rx_buf);
|
|
|
|
if (c == CR)
|
|
c = LF; // Read character
|
|
|
|
if (c == BACKSPACE || c == DEL) // Process backspace
|
|
{
|
|
if (count != 0)
|
|
{
|
|
count--;
|
|
if (g_echo_serial)
|
|
{
|
|
__io_putchar(0x08); // Send Backspace and erase previous character
|
|
__io_putchar(' ');
|
|
__io_putchar(0x08);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_echo_serial)
|
|
{
|
|
__io_putchar(c);
|
|
}
|
|
lineBuf[count] = c; // store character
|
|
count++;
|
|
}
|
|
|
|
if (c == LF)
|
|
{
|
|
lineBuf[count] = 0;
|
|
res = 1;
|
|
count = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// return the string without waiting for the CR if the line is too long
|
|
lineBuf[count] = 0;
|
|
count = 0;
|
|
return 1;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void USART1_IRQHandler(void)
|
|
{
|
|
// Check Receive Not Empty interrupt enabled and active
|
|
if ((USART1->CR1 & USART_CR1_RXNEIE) && (USART1->ISR & USART_ISR_RXNE))
|
|
{
|
|
// Read the character from the serial port
|
|
uint8_t c = (uint8_t)(USART1->RDR);
|
|
|
|
// If the buffer is not full add the character otherwise it will be discarded
|
|
if (!is_ring_buf_full(&g_rx_buf))
|
|
{
|
|
ring_buf_put(&g_rx_buf, c);
|
|
}
|
|
}
|
|
|
|
// Check Transmit Empty interrupt enabled and active
|
|
if ((USART1->CR1 & USART_CR1_TXEIE) && (USART1->ISR & USART_ISR_TXE))
|
|
{
|
|
// Send the next character
|
|
if (!is_ring_buf_empty(&g_tx_buf))
|
|
{
|
|
USART1->TDR = ring_buf_get(&g_tx_buf);
|
|
}
|
|
else
|
|
{
|
|
|
|
USART1->CR1 &= ~USART_CR1_TXEIE; // Disable the TXE interrupt
|
|
USART1->CR1 |= USART_CR1_TCIE; // Enable the TC interrupt
|
|
g_tx_sending = 0;
|
|
}
|
|
}
|
|
|
|
// Check Transmission Complete interrupt enabled and active
|
|
if ((USART1->CR1 & USART_CR1_TCIE) && (USART1->ISR, USART_ISR_TC))
|
|
{
|
|
USART1->ICR = USART_ICR_TCCF; // Clear the TC flag
|
|
|
|
if (g_tx_buf.count == 0)
|
|
{
|
|
USART1->CR1 &= ~USART_CR1_TCIE; // Disable the TC interrupt
|
|
g_tx_sending = 0;
|
|
}
|
|
}
|
|
}
|