You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

606 lines
13 KiB

/*
*
@file serial.c
@brief UART functions for EVBAVR VER 1.0 (AVR-GCC Compiler)
*
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "types.h"
#include "serial.h"
#ifndef __STDIO_FDEVOPEN_COMPAT_12
typedef struct _UARTHANDLER
{
char (*uart_get_handler)(FILE *);
void (*uart_put_handler)(char, FILE *);
}UARTHANDLER;
#else
typedef struct _UARTHANDLER
{
char (*uart_get_handler)(void);
void (*uart_put_handler)(char);
}UARTHANDLER;
#endif
#define SET_MY_XOFF_STATE(X) (bXONOFF[X] |= 0x01)
#define SET_MY_XON_STATE(X) (bXONOFF[X] &= ~(0x01))
#define SET_PEER_XOFF_STATE(X) (bXONOFF[X] |= 0x02)
#define SET_PEER_XON_STATE(X) (bXONOFF[X] &= ~(0x02))
static u_char sio_rxd[UART_DEVICE_CNT][MAX_SIO_COUNT];
static int sio_head[UART_DEVICE_CNT]; /**< a pointer to serial Rx buffer */
static int sio_tail[UART_DEVICE_CNT]; /**< a pointer to serial Rx buffer */
static u_char SIO_FLOW[UART_DEVICE_CNT];
static u_char bXONOFF[UART_DEVICE_CNT]; /**< XON/XOFF flag bit : 0 bit(1-MY XOFF State, 0-MY XON State), 1 bit(1 - Peer XOFF, 0-Peer XON) */
static UARTHANDLER uart_handler[UART_DEVICE_CNT];
#ifndef __STDIO_FDEVOPEN_COMPAT_12
extern char uart0_getchar(FILE *f);
extern void uart0_putchar(char c, FILE *f);
#else
extern char uart0_getchar(void);
extern void uart0_putchar(char c);
#endif
#if (__COMPILER_VERSION__ == __WINAVR_20050214__)
static void uart0_irq(void);
void SIG_UART0_RECV( void ) __attribute__ ((signal));
void SIG_UART0_RECV( void )
{
uart0_irq();
}
/**
@brief ATmega128 UART Rx ISR
This function is the signal handler for receive complete interrupt.
for UART0 Internal Function
*/
static void uart0_irq(void)
{
sio_rxd[0][sio_head[0]] = UDR0; /* read RX data from UART0 */
if(SIO_FLOW[0])
{
if(sio_rxd[0][sio_head[0]] == XOFF_CHAR)
SET_PEER_XOFF_STATE(0);
else if(sio_rxd[0][sio_head[0]] == XON_CHAR)
SET_PEER_XON_STATE(0);
else sio_head[0]++;
}
else sio_head[0]++;
if (sio_head[0] == sio_tail[0])
{
if(SIO_FLOW[0])
{
while (!(UCSR0A & 0x20)) ;
UDR0 = XOFF_CHAR;
SET_MY_XOFF_STATE(0);
}
sio_head[0]--; /* buffer full. */
}
if (sio_head[0] >= MAX_SIO_COUNT) /* for ring buffer */
{
sio_head[0] = 0;
if (sio_head[0] == sio_tail[0]) sio_head[0] = MAX_SIO_COUNT;
}
}
#else
/**
@brief ATmega128 UART Rx ISR
This function is the signal handler for receive complete interrupt.
for UART0 Internal Function
*/
ISR(USART0_RX_vect) /* Interrupt Service Routine for AVR GCC ver. 3.4.6*/
{
sio_rxd[0][sio_head[0]] = UDR0; /* read RX data from UART0 */
if(SIO_FLOW[0])
{
if(sio_rxd[0][sio_head[0]] == XOFF_CHAR)
SET_PEER_XOFF_STATE(0);
else if(sio_rxd[0][sio_head[0]] == XON_CHAR)
SET_PEER_XON_STATE(0);
else sio_head[0]++;
}
else sio_head[0]++;
if (sio_head[0] == sio_tail[0])
{
if(SIO_FLOW[0])
{
while (!(UCSR0A & 0x20)) ;
UDR0 = XOFF_CHAR;
SET_MY_XOFF_STATE(0);
}
sio_head[0]--; /* buffer full. */
}
if (sio_head[0] >= MAX_SIO_COUNT) /* for ring buffer */
{
sio_head[0] = 0;
if (sio_head[0] == sio_tail[0]) sio_head[0] = MAX_SIO_COUNT;
}
}
#endif
#ifdef SUPPORT_UART_ONE /* UART1 */
#if (__COMPILER_VERSION__ == __WINAVR_20050214__)
static void uart1_irq(void);
void SIG_UART1_RECV( void ) __attribute__ ((signal));
void SIG_UART1_RECV( void )
{
uart1_irq();
}
/**
@brief ATmega128 UART Rx ISR
This function is the signal handler for receive complete interrupt.
for UART1 Internal Function
*/
static void uart1_irq(void)
{
sio_rxd[1][sio_head[1]] = UDR1; /* read RX data from UART0 */
if(SIO_FLOW[1])
{
if(sio_rxd[1][sio_head[1]] == XOFF_CHAR)
SET_PEER_XOFF_STATE(1);
else if(sio_rxd[1][sio_head[1]] == XON_CHAR)
SET_PEER_XON_STATE(1);
else sio_head[1]++;
}
else sio_head[1]++;
if (sio_head[1] == sio_tail[1])
{
if(SIO_FLOW[1])
{
while (!(UCSR1A & 0x20)) ;
UDR1 = XOFF_CHAR;
SET_MY_XOFF_STATE(1);
}
sio_head[1]--; /* buffer full. */
}
if (sio_head[1] >= MAX_SIO_COUNT) /* for ring buffer */
{
sio_head[1] = 0;
if (sio_head[1] == sio_tail[1]) sio_head[1] = MAX_SIO_COUNT;
}
}
#else
/**
@brief ATmega128 UART Rx ISR
This function is the signal handler for receive complete interrupt.
for UART1 Internal Function
*/
ISR(USART1_RX_vect) /* Interrupt Service Routine for AVR GCC ver. 3.4.6*/
{
sio_rxd[1][sio_head[1]] = UDR1; /* read RX data from UART0 */
if(SIO_FLOW[1])
{
if(sio_rxd[1][sio_head[1]] == XOFF_CHAR)
SET_PEER_XOFF_STATE(1);
else if(sio_rxd[1][sio_head[1]] == XON_CHAR)
SET_PEER_XON_STATE(1);
else sio_head[1]++;
}
else sio_head[1]++;
if (sio_head[1] == sio_tail[1])
{
if(SIO_FLOW[1])
{
while (!(UCSR1A & 0x20)) ;
UDR1 = XOFF_CHAR;
SET_MY_XOFF_STATE(1);
}
sio_head[1]--; /* buffer full. */
}
if (sio_head[1] >= MAX_SIO_COUNT) /* for ring buffer */
{
sio_head[1] = 0;
if (sio_head[1] == sio_tail[1]) sio_head[1] = MAX_SIO_COUNT;
}
}
#endif
#endif
/**
@brief This function initializes the UART of ATmega64
*/
void uart_init(
u_char uart, /**< UART Device Index(0,1) */
u_char baud_index /**< UART BaudRate Index(0:2400,...,11:500000) */
)
{
/* enable RxD/TxD and RX INT */
u_int uart_select_baud = UART_BAUD_SELECT(baud_index);
if(uart == 0) /* uart == 0( first serial ) */
{
UCSR0B = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
UBRR0H = (u_char) ((uart_select_baud >> 8) & 0xFF);
UBRR0L = (u_char) (uart_select_baud & 0xFF);
uart_handler[0].uart_get_handler = uart0_getchar;
uart_handler[0].uart_put_handler = uart0_putchar;
#if defined(__STDIO_FDEVOPEN_COMPAT_12)
/*
* Declare prototype for the discontinued version of fdevopen() that
* has been in use up to avr-libc 1.2.x. The new implementation has
* some backwards compatibility with the old version.
*/
fdevopen((void *)uart0_putchar, (void *)uart0_getchar, 0);
#else /* !defined(__STDIO_FDEVOPEN_COMPAT_12) */
/* New prototype for avr-libc 1.4 and above. */
/* fdevopen((void *)uart0_putchar_avrlibv1_4, (void *)uart0_getchar_avrlibv1_4); */
fdevopen((void *)uart0_putchar, (void *)uart0_getchar);
#endif /* defined(__STDIO_FDEVOPEN_COMPAT_12) */
}
#ifdef SUPPORT_UART_ONE
else if ( uart == 1 )
{
UCSR1B = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
/* set baud rate */
UBRR1H = (u_char) ((uart_select_baud >> 8) & 0xFF);
UBRR1L = (u_char) (uart_select_baud& 0xFF);
uart_handler[1].uart_get_handler = uart1_getchar;
uart_handler[1].uart_put_handler = uart1_putchar;
#if defined(__STDIO_FDEVOPEN_COMPAT_12)
/*
* Declare prototype for the discontinued version of fdevopen() that
* has been in use up to avr-libc 1.2.x. The new implementation has
* some backwards compatibility with the old version.
*/
fdevopen((void *)uart1_putchar, (void *)uart1_getchar, 0);
#else /* !defined(__STDIO_FDEVOPEN_COMPAT_12) */
/* New prototype for avr-libc 1.4 and above. */
/* fdevopen((void *)uart0_putchar_avrlibv1_4, (void *)uart0_getchar_avrlibv1_4); */
fdevopen((void *)uart1_putchar, (void *)uart1_getchar);
#endif /* defined(__STDIO_FDEVOPEN_COMPAT_12) */
}
#endif
else
{
return;
}
sio_head[uart] = 0;
sio_tail[uart] = 0;
SIO_FLOW[uart] = 0;
bXONOFF[uart] = 0;
}
////---- END_MODIFY
void uart_databit(u_char uart, u_char dbit)
{
if(uart == 0)
{
UCSR0C |= 1 << 3;
if(!dbit) UCSR0C &= ~(1<<1); // 7bit
else UCSR0C |= (1<<1); // 8bit;
}
#ifdef SUPPORT_UART_ONE
else if ( uart == 1 )
{
UCSR1C |= 1 << 3;
if(!dbit) UCSR1C &= ~(1<<1); // 7bit
else UCSR1C |= (1<<1); // 8bit;
}
#endif
}
void uart_stopbit(u_char uart,u_char sbit)
{
if(uart == 0)
{
if(!sbit) UCSR0C &= ~(1 << 3); // 1 BIT
else UCSR0C |= (1 << 3); // 2 BIT
}
#ifdef SUPPORT_UART_ONE
else if ( uart == 1 )
{
if(!sbit) UCSR1C &= ~(1 << 3); // 1 BIT
else UCSR1C |= (1 << 3); // 2 BIT}
}
#endif
}
void uart_paritybit(u_char uart,u_char pbit)
{
if(uart == 0)
{
if(!pbit) UCSR0C &= ~(3 << 4); // none
else if (pbit ==1) UCSR0C &= ~(1 << 4); // even
else UCSR0C |= (3 << 4); // odd
}
#ifdef SUPPORT_UART_ONE
else if ( uart == 1 )
{
if(!pbit) UCSR1C &= ~(3 << 4); // none
else if (pbit ==1) UCSR1C &= ~(1 << 4); // even
else UCSR1C |= (3 << 4); // odd
}
#endif
}
void uart_flowctrl(u_char uart,u_char flow)
{
if ( uart < UART_DEVICE_CNT )
SIO_FLOW[uart] = flow;
}
/**
@brief CHECK RX
@return retunr RX size, if there is Rx.
This function checks if there is Rx. \n
if not, return 0
*/
u_int uart_keyhit(u_char uart)
{
if ( uart >= UART_DEVICE_CNT )
return 0;
if(sio_head[uart] >= sio_tail[uart] ) return (sio_head[uart]-sio_tail[uart]);
else return (MAX_SIO_COUNT-(sio_tail[uart]-sio_head[uart]));
}
/**
@brief WRITE A CHARACTER
This function sends a character through UART0.
*/
#ifndef __STDIO_FDEVOPEN_COMPAT_12
void uart0_putchar(char c, FILE *f)
#else
void uart0_putchar(char c)
#endif
{
while(SIO_FLOW[0] && (bXONOFF[0] & 0x02)); // If Peer XOFF STATE
while (!(UCSR0A & 0x20)) ;
UDR0 = c;
}
/**
@brief READ A CHARACTER
@return c - is a character to read
This function gets a character from UART0.
*/
#ifndef __STDIO_FDEVOPEN_COMPAT_12
char uart0_getchar(FILE *f)
#else
char uart0_getchar(void)
#endif
{
char c;
while (sio_head[0] == sio_tail[0]);
c = sio_rxd[0][sio_tail[0]++];
if(SIO_FLOW[0] && (bXONOFF[0] & 0x01)) // IF MY XOFF STATE
{
while (!(UCSR0A & 0x20)) ;
UDR0 = XON_CHAR;
SET_MY_XON_STATE(0);
}
if (sio_tail[0] >= MAX_SIO_COUNT) sio_tail[0] = 0;
return c;
}
#ifdef SUPPORT_UART_ONE
/**
@brief WRITE A CHARACTER
This function sends a character through UART1.
*/
#ifndef __STDIO_FDEVOPEN_COMPAT_12
void uart1_putchar(char c, FILE *f)
#else
void uart1_putchar(char c)
#endif
{
while(SIO_FLOW[1] && (bXONOFF[1] & 0x02)); // If Peer XOFF STATE
while (!(UCSR1A & 0x20)) ;
UDR1 = c;
}
/**
@brief READ A CHARACTER
@return c - is a character to read
This function gets a character from UART1.
*/
#ifndef __STDIO_FDEVOPEN_COMPAT_12
char uart1_getchar(FILE *f)
#else
char uart1_getchar(void)
#endif
{
char c;
while (sio_head[1] == sio_tail[1]);
c = sio_rxd[1][sio_tail[1]++];
if(SIO_FLOW[1] && (bXONOFF[1] & 0x01)) // IF MY XOFF STATE
{
while (!(UCSR1A & 0x20)) ;
UDR1 = XON_CHAR;
SET_MY_XON_STATE(1);
}
if (sio_tail[1] >= MAX_SIO_COUNT) sio_tail[1] = 0;
return c;
}
#endif /* support UART1 */
/**
@brief WRITE A CHARACTER
This function sends a string to UART.
*/
void uart_puts(u_char uart, char * str)
{
int i = 0;
if ( uart >= UART_DEVICE_CNT )
return;
#ifndef __STDIO_FDEVOPEN_COMPAT_12
while (str[i]) (*uart_handler[uart].uart_put_handler)(str[i++],NULL);
#else
while (str[i]) (*uart_handler[uart].uart_put_handler)(str[i++]);
#endif
}
/**
@brief READ A CHARACTER
@return str - is a pointer to the string to read
This function gets a string from UART.
*/
int uart_gets(u_char uart, char * str, char bpasswordtype, int max_len)
{
char c;
char * tsrc = str;
char IsFirst = 1;
int len = 0;
if ( uart >= UART_DEVICE_CNT )
return 0;
#ifndef __STDIO_FDEVOPEN_COMPAT_12
while ((c = (*uart_handler[uart].uart_get_handler)(NULL)) != 0x0D)
#else
while ((c = (*uart_handler[uart].uart_get_handler)()) != 0x0D)
#endif
{
if (IsFirst && c=='!')
{
#ifndef __STDIO_FDEVOPEN_COMPAT_12
while(*str != '\0') (*uart_handler[uart].uart_put_handler)(*str++,NULL);
#else
while(*str != '\0') (*uart_handler[uart].uart_put_handler)(*str++);
#endif
IsFirst = 0;
len++;
continue;
}
if (c == 0x08 && tsrc != str)
{
#ifndef __STDIO_FDEVOPEN_COMPAT_12
(*uart_handler[uart].uart_put_handler)(0x08,NULL);
(*uart_handler[uart].uart_put_handler)(' ',NULL);
(*uart_handler[uart].uart_put_handler)(0x08,NULL);
#else
(*uart_handler[uart].uart_put_handler)(0x08);
(*uart_handler[uart].uart_put_handler)(' ');
(*uart_handler[uart].uart_put_handler)(0x08);
#endif
str--;
len--;
continue;
}
else if (c == 0x1B)
{
while (tsrc != str)
{
#ifndef __STDIO_FDEVOPEN_COMPAT_12
(*uart_handler[uart].uart_put_handler)(0x08,NULL);
(*uart_handler[uart].uart_put_handler)(' ',NULL);
(*uart_handler[uart].uart_put_handler)(0x08,NULL);
#else
(*uart_handler[uart].uart_put_handler)(0x08);
(*uart_handler[uart].uart_put_handler)(' ');
(*uart_handler[uart].uart_put_handler)(0x08);
#endif
str--;
len--;
}
IsFirst = 1;
continue;
}
else if ((c < 32 || c > 126) && c != '\t') continue;
if(len < max_len)
{
#ifndef __STDIO_FDEVOPEN_COMPAT_12
if(bpasswordtype) (*uart_handler[uart].uart_put_handler)('*',NULL);
else (*uart_handler[uart].uart_put_handler)(c,NULL);
#else
if(bpasswordtype) (*uart_handler[uart].uart_put_handler)('*');
else (*uart_handler[uart].uart_put_handler)(c);
#endif
*str++ = c;
len++;
IsFirst = 0;
}
}
*str = '\0';
uart_puts(uart,"\r\n");
return len;
}
/**
@brief GET A BYTE
This function flush rx buffer of serial
*/
void uart_flush_rx(u_char uart)
{
if ( uart >= UART_DEVICE_CNT )
return;
sio_head[uart] = sio_tail[uart];
}