mirror of
https://github.com/Fishwaldo/bl_mcu_sdk.git
synced 2025-07-12 07:48:42 +00:00
383 lines
12 KiB
C
383 lines
12 KiB
C
#include <errno.h>
|
|
#include <reent.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "bflb_uart.h"
|
|
|
|
/** @addtogroup ttyin_config
|
|
-----------------------------------------------------------------------------
|
|
* @{
|
|
----------------------------------------------------------------------------*/
|
|
/*!< the following configuration is only valid for tty input */
|
|
|
|
/*!< block mode or nonblock mode */
|
|
#ifndef CONFIG_TTYIN_NONBLOCK
|
|
#define CONFIG_TTYIN_NONBLOCK 0
|
|
#endif
|
|
|
|
/*!< use raw data */
|
|
#ifndef CONFIG_TTYIN_RAWMODE
|
|
#define CONFIG_TTYIN_RAWMODE 0
|
|
#endif
|
|
|
|
/*!< map crnl -> nl */
|
|
#ifndef CONFIG_TTYIN_CRNL2NL
|
|
#define CONFIG_TTYIN_CRNL2NL 1
|
|
#endif
|
|
|
|
/*!< map crnl -> cr */
|
|
#ifndef CONFIG_TTYIN_CRNL2CR
|
|
#define CONFIG_TTYIN_CRNL2CR 0
|
|
#endif
|
|
|
|
/*!< map nlcr -> nl */
|
|
#ifndef CONFIG_TTYIN_NLCR2NL
|
|
#define CONFIG_TTYIN_NLCR2NL 1
|
|
#endif
|
|
|
|
/*!< map nlcr -> cr */
|
|
#ifndef CONFIG_TTYIN_NLCR2CR
|
|
#define CONFIG_TTYIN_NLCR2CR 0
|
|
#endif
|
|
|
|
/*!< map cr -> nl */
|
|
#ifndef CONFIG_TTYIN_CR2NL
|
|
#define CONFIG_TTYIN_CR2NL 1
|
|
#endif
|
|
|
|
/*!< map nl -> cr */
|
|
#ifndef CONFIG_TTYIN_NL2CR
|
|
#define CONFIG_TTYIN_NL2CR 0
|
|
#endif
|
|
/*---------------------------------------------------------------------------
|
|
* @} ttyin_config
|
|
----------------------------------------------------------------------------*/
|
|
|
|
/** @addtogroup ttyin_fifo
|
|
-----------------------------------------------------------------------------
|
|
* @{
|
|
----------------------------------------------------------------------------*/
|
|
struct _ttyin_fifo {
|
|
volatile uint32_t in;
|
|
volatile uint32_t out;
|
|
volatile uint32_t mask;
|
|
volatile void *data;
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* @brief macro to define and init a fifo object
|
|
*
|
|
* @param name name of the fifo
|
|
* @param size the number of elements in the fifo,
|
|
* this must be a power of 2 !!!
|
|
*****************************************************************************/
|
|
#define TTYIN_FIFO_DEFINE(name, size) \
|
|
struct { \
|
|
struct _ttyin_fifo fifo; \
|
|
uint8_t buf[(((size) < 2) || ((size) & ((size)-1))) ? -1 : (size)]; \
|
|
}(name) = { \
|
|
.fifo.in = 0, \
|
|
.fifo.out = 0, \
|
|
.fifo.mask = (size)-1, \
|
|
.fifo.data = (name).buf \
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief get fifo used space size
|
|
*
|
|
* @param[in] fifo fifo object
|
|
*
|
|
* @retval uint32_t used space size
|
|
*****************************************************************************/
|
|
static inline uint32_t _ttyin_fifo_used(struct _ttyin_fifo *fifo)
|
|
{
|
|
return fifo->in - fifo->out;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief get fifo unused space size
|
|
*
|
|
* @param[in] fifo fifo object
|
|
*
|
|
* @retval uint32_t unused space size
|
|
*****************************************************************************/
|
|
static inline uint32_t _ttyin_fifo_free(struct _ttyin_fifo *fifo)
|
|
{
|
|
return (fifo->mask + 1) - (fifo->in - fifo->out);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief returns true if the fifo is full
|
|
*
|
|
* @param[in] fifo fifo object
|
|
*
|
|
* @retval bool
|
|
*****************************************************************************/
|
|
static inline bool _ttyin_fifo_is_full(struct _ttyin_fifo *fifo)
|
|
{
|
|
return _ttyin_fifo_used(fifo) > fifo->mask;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief returns true if the fifo is empty
|
|
*
|
|
* @param[in] name fifo object
|
|
*
|
|
* @retval bool
|
|
*****************************************************************************/
|
|
static inline bool _ttyin_fifo_is_empty(struct _ttyin_fifo *fifo)
|
|
{
|
|
return fifo->in == fifo->out;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief put byte into the fifo
|
|
*
|
|
* @param[in] name fifo object
|
|
* @param[in] ch data
|
|
*
|
|
*****************************************************************************/
|
|
static inline void _ttyin_fifo_put(struct _ttyin_fifo *fifo, uint8_t ch)
|
|
{
|
|
#if defined(CONFIG_TTYIN_CR2NL) && CONFIG_TTYIN_CR2NL
|
|
ch = (ch == '\r') ? '\n' : ch;
|
|
#elif defined(CONFIG_TTYIN_NL2CR) && CONFIG_TTYIN_NL2CR
|
|
ch = (ch == '\n') ? '\r' : ch;
|
|
#endif
|
|
|
|
if (!_ttyin_fifo_is_full(fifo)) {
|
|
((volatile uint8_t *)(fifo->data))[fifo->in & fifo->mask] = ch;
|
|
fifo->in++;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief get byte from the fifo
|
|
*
|
|
* @param[in] fifo fifo object
|
|
*
|
|
* @retval int data
|
|
*****************************************************************************/
|
|
static inline int _ttyin_fifo_get(struct _ttyin_fifo *fifo)
|
|
{
|
|
register int ch = -1;
|
|
|
|
#if defined(CONFIG_TTYIN_NONBLOCK) && CONFIG_TTYIN_NONBLOCK
|
|
if (!_ttyin_fifo_is_empty(fifo))
|
|
#else
|
|
while (_ttyin_fifo_is_empty(fifo)) {}
|
|
#endif
|
|
{
|
|
ch = ((volatile uint8_t *)(fifo->data))[fifo->out & fifo->mask];
|
|
fifo->out++;
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
#define ttyin_fifo_used(__fifo) _ttyin_fifo_used(&((__fifo).fifo))
|
|
#define ttyin_fifo_free(__fifo) _ttyin_fifo_free(&((__fifo).fifo))
|
|
#define ttyin_fifo_is_full(__fifo) _ttyin_fifo_is_full(&((__fifo).fifo))
|
|
#define ttyin_fifo_is_empty(__fifo) _ttyin_fifo_is_empty(&((__fifo).fifo))
|
|
#define ttyin_fifo_put(__fifo, __ch) _ttyin_fifo_put(&((__fifo).fifo), (__ch))
|
|
#define ttyin_fifo_get(__fifo) _ttyin_fifo_get(&((__fifo).fifo))
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* @} ttyin_fifo
|
|
----------------------------------------------------------------------------*/
|
|
struct bflb_device_s *console = NULL;
|
|
|
|
static TTYIN_FIFO_DEFINE(stdin_fifo, 512);
|
|
|
|
void console_receive_isr(int irq, void *arg)
|
|
{
|
|
uint32_t intstatus = bflb_uart_get_intstatus(console);
|
|
|
|
if (intstatus & UART_INTSTS_RX_FIFO) {
|
|
while (bflb_uart_rxavailable(console)) {
|
|
ttyin_fifo_put(stdin_fifo, bflb_uart_getchar(console));
|
|
}
|
|
}
|
|
|
|
if (intstatus & UART_INTSTS_RTO) {
|
|
while (bflb_uart_rxavailable(console)) {
|
|
ttyin_fifo_put(stdin_fifo, bflb_uart_getchar(console));
|
|
}
|
|
bflb_uart_int_clear(console, UART_INTCLR_RTO);
|
|
}
|
|
}
|
|
|
|
void bflb_uart_set_console(struct bflb_device_s *dev)
|
|
{
|
|
console = dev;
|
|
bflb_uart_rxint_mask(console, false);
|
|
bflb_irq_attach(console->irq_num, console_receive_isr, console);
|
|
bflb_irq_enable(console->irq_num);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief open
|
|
*
|
|
* @param[in] reent pointer to reentrant struct
|
|
* @param[in] path file path string pointer
|
|
* @param[in] flags open mode in fcntl.h
|
|
* @param[in] mode permission mode
|
|
*
|
|
* @retval int >=0:fd -1:Error
|
|
*****************************************************************************/
|
|
int _open_tty_r(struct _reent *reent, const char *path, int flags, int mode)
|
|
{
|
|
if (strncmp("/dev/null", path, 9) == 0) {
|
|
return 0x3ff;
|
|
} else if (strncmp("/dev/stdin", path, 10) == 0) {
|
|
return 0;
|
|
} else if (strncmp("/dev/stdout", path, 11) == 0) {
|
|
return 1;
|
|
} else if (strncmp("/dev/stderr", path, 11) == 0) {
|
|
return 2;
|
|
} else {
|
|
reent->_errno = ENOENT;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief close
|
|
*
|
|
* @param[in] reent pointer to reentrant struct
|
|
* @param[in] fd file descriptors
|
|
*
|
|
* @retval int 0:Success -1:Error
|
|
*****************************************************************************/
|
|
int _close_tty_r(struct _reent *reent, int fd)
|
|
{
|
|
if (fd == 0x3ff) {
|
|
return 0;
|
|
} else if (fd == 0) {
|
|
return 0;
|
|
} else if (fd == 1) {
|
|
return 0;
|
|
} else if (fd == 2) {
|
|
return 0;
|
|
} else {
|
|
reent->_errno = EBADF;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief read
|
|
*
|
|
* @param[in] reent pointer to reentrant struct
|
|
* @param[in] fd file descriptors
|
|
* @param[in] ptr pointer to buffer
|
|
* @param[in] size number of bytes read
|
|
*
|
|
* @retval _ssize_t actual number of bytes read
|
|
*****************************************************************************/
|
|
_ssize_t _read_tty_r(struct _reent *reent, int fd, void *ptr, size_t size)
|
|
{
|
|
if (fd == 0x3ff) {
|
|
return -1;
|
|
} else if (fd == 0) {
|
|
int ch;
|
|
|
|
for (size_t i = 0; i < size; i++) {
|
|
if ((ch = ttyin_fifo_get(stdin_fifo)) <= -1) {
|
|
return i;
|
|
} else {
|
|
((uint8_t *)ptr)[i] = ch;
|
|
bflb_uart_putchar(console, ch);
|
|
}
|
|
}
|
|
|
|
return size;
|
|
} else if ((fd == 1) || (fd == 2)) {
|
|
reent->_errno = EACCES;
|
|
return -1;
|
|
} else {
|
|
reent->_errno = EBADF;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief write
|
|
*
|
|
* @param[in] reent pointer to reentrant struct
|
|
* @param[in] fd file descriptors
|
|
* @param[in] ptr pointer to buffer
|
|
* @param[in] size number of bytes write
|
|
*
|
|
* @retval _ssize_t actual number of bytes write
|
|
*****************************************************************************/
|
|
_ssize_t _write_tty_r(struct _reent *reent, int fd, const void *ptr, size_t size)
|
|
{
|
|
if (fd == 0x3ff) {
|
|
return size;
|
|
} else if (fd == 0) {
|
|
reent->_errno = EACCES;
|
|
return -1;
|
|
} else if ((fd == 1) || (fd == 2)) {
|
|
for (size_t i = 0; i < size; i++) {
|
|
bflb_uart_putchar(console, ((uint8_t *)ptr)[i]);
|
|
}
|
|
return size;
|
|
} else {
|
|
reent->_errno = EBADF;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief fstat (not supported)
|
|
*
|
|
* @param[in] reent pointer to reentrant struct
|
|
* @param[in] fd file descriptors
|
|
* @param[out] st file stat
|
|
*
|
|
* @retval int 0:Success -1:Error
|
|
*****************************************************************************/
|
|
int _fstat_tty_r(struct _reent *reent, int fd, struct stat *st)
|
|
{
|
|
if (fd == 0x3ff) {
|
|
st->st_mode = 0666 | S_IFCHR;
|
|
return 0;
|
|
} else if (fd == 0) {
|
|
st->st_mode = 0444 | S_IFCHR;
|
|
return 0;
|
|
} else if ((fd == 1) || (fd == 2)) {
|
|
st->st_mode = 0222 | S_IFCHR;
|
|
return 0;
|
|
} else {
|
|
reent->_errno = EBADF;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @brief stat
|
|
*
|
|
* @param[in] reent pointer to reentrant struct
|
|
* @param[in] path file path
|
|
* @param[out] st file stat
|
|
*
|
|
* @retval int 0:Success -1:Error
|
|
*****************************************************************************/
|
|
int _stat_tty_r(struct _reent *reent, const char *path, struct stat *st)
|
|
{
|
|
if (strncmp("/dev/null", path, 9) == 0) {
|
|
return _fstat_tty_r(reent, 0x3ff, st);
|
|
} else if (strncmp("/dev/stdin", path, 10) == 0) {
|
|
return _fstat_tty_r(reent, 0, st);
|
|
} else if (strncmp("/dev/stdout", path, 11) == 0) {
|
|
return _fstat_tty_r(reent, 1, st);
|
|
} else if (strncmp("/dev/stderr", path, 11) == 0) {
|
|
return _fstat_tty_r(reent, 2, st);
|
|
} else {
|
|
reent->_errno = EBADF;
|
|
return -1;
|
|
}
|
|
}
|