/************************************************************************/ /* */ /* File: avr/usart.c */ /* Description: serial line device. */ /* Version: 1.0 */ /* Author: Otto Mattik */ /* */ /* (C)Copyright Otto Mattik 2014-2021. */ /* */ /* This file is a part of 'armen' (a tiny operating system). */ /* 'armen' is distributed under the CeCILL-V2.1 licence. For more */ /* details about this licence, please visit the website cecill.info */ /* */ /************************************************************************/ #ifndef AVR_UART_C #error "do not use this code directly, it must be included via avr_uart.c" #endif /* #define OUTPUT_INTERRUPT */ #include #include /* * the uart is configured with 8 data bits, no parity and 1 stop bit. */ #if defined(__AVR_ATtiny841__) #define UART0_INPUT_PIN PA2 /* receive */ #define UART0_OUTPUT_PIN PA1 /* transmit */ #define UART0_CONFIG_PINS() (\ DDRA = (DDRA|(1<>8, UBRR0L = (b)&0xFF\ ) #define UART0_CONFIG_DEVICE() (\ UCSR0B = (1<>8, UBRR1L = (b)&0xFF\ ) #define UART1_CONFIG_DEVICE() (\ UCSR1B = (1<>8, UBRR2L = (b)&0xFF\ ) #define UART2_CONFIG_DEVICE() (\ UCSR2B = (1<>8, UBRR3L = (b)&0xFF\ ) #define UART3_CONFIG_DEVICE() (\ UCSR3B = (1<= 2) ISR( UART1_INPUT_INT ) { uint8_t byte = UART1_RX_BYTE; _uart_recv_byte( 1, byte ); } #endif #if (ARMEN_UARTS >= 3) ISR( UART2_INPUT_INT ) { uint8_t byte = UART2_RX_BYTE; _uart_recv_byte( 2, byte ); } #endif #if (ARMEN_UARTS == 4) ISR( UART3_INPUT_INT ) { uint8_t byte = UART3_RX_BYTE; _uart_recv_byte( 3, byte ); } #endif /* * occurs at end of byte transmission */ #ifdef OUTPUT_INTERRUPT ISR( UART0_OUTPUT_INT ) { uarts[0].state &= ~UART_TX_PROGRESS; UART0_TX_INT_DISABLE( ); } #if (ARMEN_UARTS >= 2) ISR( UART1_OUTPUT_INT ) { uarts[1].state &= ~UART_TX_PROGRESS; UART1_TX_INT_DISABLE( ); } #endif #if (ARMEN_UARTS >= 3) ISR( UART2_OUTPUT_INT ) { uarts[2].state &= ~UART_TX_PROGRESS; UART2_TX_INT_DISABLE( ); } #endif #if (ARMEN_UARTS == 4) ISR( UART3_OUTPUT_INT ) { uarts[3].state &= ~UART_TX_PROGRESS; UART3_TX_INT_DISABLE( ); } #endif #endif /* * initialize device * * input: * device identifier * config uart configuration * output: * 0 if success, otherwise -1 */ static int8_t _uart_open( uint8_t device, uint8_t config ) { uint8_t bauds = config & BAUDRATE; uint16_t ubrr = uart_bauds[bauds]; #ifdef CHECK_PARAM if( (uarts[device].state & UART_OPEN) != 0 || bauds > B115200 ) return( -1 ); #endif uarts[device].rx_head = uarts[device].rx_tail = 0; uarts[device].state = (config & UART_CONFIG_MASK) | UART_OPEN; uarts[device].rx_head = uarts[device].rx_tail = 0; if( device == 0 ) { UART0_CONFIG( ubrr ); UART0_RX_INT_ENABLE( ); } #if (ARMEN_UARTS >= 2) else if( device == 1 ) { UART1_CONFIG( ubrr ); UART1_RX_INT_ENABLE( ); } #endif #if (ARMEN_UARTS >= 3) else if( device == 2 ) { UART2_CONFIG( ubrr ); UART2_RX_INT_ENABLE( ); } #endif #if (ARMEN_UARTS == 4) else { UART3_CONFIG( ubrr ); UART3_RX_INT_ENABLE( ); } #endif } /* * release device * * input: * device identifier * output: * 0 if success, otherwise -1 */ static int8_t _uart_close( uint8_t device ) { #ifdef CHECK_PARAM if( (uarts[device].state & UART_OPEN) == 0 ) return( -1 ); #endif if( device == 0 ) { UART0_RX_INT_DISABLE( ); #ifdef OUTPUT_INTERRUPT UART0_TX_INT_DISABLE( ); #endif } #if (ARMEN_UARTS >= 2) else if( device == 1 ) { UART1_RX_INT_DISABLE( ); #ifdef OUTPUT_INTERRUPT UART1_TX_INT_DISABLE( ); #endif } #endif #if (ARMEN_UARTS >= 3) else if( device == 2 ) { UART2_RX_INT_DISABLE( ); #ifdef OUTPUT_INTERRUPT UART2_TX_INT_DISABLE( ); #endif } #endif #if (ARMEN_UARTS == 4) else { UART3_RX_INT_DISABLE( ); #ifdef OUTPUT_INTERRUPT UART3_TX_INT_DISABLE( ); #endif } #endif uarts[device].state = 0; uarts[device].rx_head = uarts[device].rx_tail = 0; return( 0 ); } /* * read from device * * input: * device identifier * byte address of byte to read * output: * 0 if success, otherwise -1 */ static int8_t _uart_read( uint8_t device, uint8_t* byte ) { uint8_t tail; #ifdef CHECK_PARAM if( (uarts[device].state & UART_OPEN) == 0 || byte == (uint8_t*)0 ) return( -1 ); #endif tail = uarts[device].rx_tail; if( tail == uarts[device].rx_head ) wait_event( EVENT_UART0 + device ); if( ++tail == (UART_RX_BUFFER_SIZE + 1) ) tail = 0; *byte = uarts[device].rx_buffer[tail]; uarts[device].rx_tail = tail; return( 0 ); } /* * write to device * * input: * device identifier * byte byte to write * output: * 0 if success, otherwise -1 */ static int8_t _uart_write( uint8_t device, uint8_t byte ) { if( (uarts[device].state & UART_OPEN) == 0 ) return( -1 ); #ifdef OUTPUT_INTERRUPT uarts[device].state |= UART_TX_PROGRESS; #endif if( uarts[device].state & ECHOO ) uarts[device].state |= UART_ECHOO_CHECK; if( device == 0 ) { #ifdef OUTPUT_INTERRUPT UART0_TX_BYTE = byte; UART0_TX_INT_ENABLE( ); #else while( UART0_TX_NOT_READY( ) ) ; UART0_TX_BYTE = byte; #endif } #if (ARMEN_UARTS >= 2) else if( device == 1 ) { #ifdef OUTPUT_INTERRUPT UART1_TX_BYTE = byte; UART1_TX_INT_ENABLE( ); #else while( UART1_TX_NOT_READY( ) ) ; UART1_TX_BYTE = byte; #endif } #endif #if (ARMEN_UARTS >= 3) else if( device == 2 ) { #ifdef OUTPUT_INTERRUPT UART2_TX_BYTE = byte; UART2_TX_INT_ENABLE( ); #else while( UART2_TX_NOT_READY( ) ) ; UART2_TX_BYTE = byte; #endif } #endif #if (ARMEN_UARTS == 4) else { #ifdef OUTPUT_INTERRUPT UART3_TX_BYTE = byte; UART3_TX_INT_ENABLE( ); #else while( UART3_TX_NOT_READY( ) ) ; UART3_TX_BYTE = byte; #endif } #endif #ifdef OUTPUT_INTERRUPT while( uarts[device].state & UART_TX_PROGRESS ) ; #else if( device == 0 ) while( UART0_TX_NOT_READY( ) ) ; #if (ARMEN_UARTS >= 2) else if( device == 1 ) while( UART1_TX_NOT_READY( ) ) ; #endif #if (ARMEN_UARTS >= 3) else if( device == 2 ) while( UART2_TX_NOT_READY( ) ) ; #endif #if (ARMEN_UARTS == 4) else while( UART3_TX_NOT_READY( ) ) ; #endif #endif if( uarts[device].state & ECHOO ) { while( uarts[device].state & UART_ECHOO_CHECK ) ; if( uarts[device].cd_byte != byte ) return( -1 ); } return( 0 ); } /* * device special feature * * input: * device identifier * request device dependent * args list of arguments * output: * 0 if success, otherwise -1 */ #ifdef UART_IOCTL static int8_t _uart_ioctl( uint8_t device, uint8_t request, va_list args ) { if( (uarts[device].state & UART_OPEN) != 0 ) { if( request == UART_GETP ) { uint8_t* p = va_arg( args, uint8_t* ); *p = uarts[device].state & UART_CONFIG_MASK; return( 0 ) } } return( -1 ); } #endif