X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=common%2Fserial.c;h=6bf730c8c7a4640fbac5f4730a79f578b2da3da8;hb=HEAD;hp=2bf6901836064ece4517047dcb8d94f70838d99f;hpb=9c37d18b9c70fdb70dfec453398c4649e9e57586;p=model-railway-devices.git diff --git a/common/serial.c b/common/serial.c index 2bf6901..6bf730c 100644 --- a/common/serial.c +++ b/common/serial.c @@ -1,22 +1,120 @@ +#include #include +#include "delay.h" +#include "ringbuffer.h" #include "serial.h" #define BIT(n) (1<<(n)) +#ifndef SERIAL_BUFSIZE +#define SERIAL_BUFSIZE 16 +#endif + +#ifdef SERIAL_ASYNC +static RINGBUFFER(rx, SERIAL_BUFSIZE); +static RINGBUFFER(tx, SERIAL_BUFSIZE); +static uint8_t rx_overrun; +#define INTERRUPTS BIT(RXCIE0) +#else +#define INTERRUPTS 0 +#endif + +static inline void set_baud(uint16_t baud) +{ + baud = (F_CPU/16+baud/2)/baud-1; + UBRR0H = baud>>8; + UBRR0L = baud; +} + void serial_init(uint16_t baud) { DDRD = (DDRD&~0x03) | 0x02; PORTD &= ~0x03; - baud = (F_CPU/16+baud/2)/baud-1; - UBRR0H = baud>>8; - UBRR0L = baud; + set_baud(baud); + UCSR0A = 0; UCSR0C = BIT(UCSZ00) | BIT(UCSZ01); // 8N1 - UCSR0B = BIT(RXEN0) | BIT(TXEN0) | BIT(RXCIE0); + UCSR0B = BIT(RXEN0) | BIT(TXEN0) | INTERRUPTS; +} + +void serial_set_baud(uint16_t baud) +{ +#ifdef SERIAL_ASYNC + while(!(UCSR0A&BIT(UDRE0))) ; +#endif + /* It's impossible to reliably find out when transmission has finished. + Wait for one character duration to be safe. */ + uint16_t delay = (UBRR0H<<8)|UBRR0L; + for(uint8_t i=0; i<40; ++i) + delay_loop16(delay); + set_baud(baud); +} + +uint8_t serial_read() +{ +#ifdef SERIAL_ASYNC + return ringbuffer_blocking_pop(rx); +#else + while(!(UCSR0A&BIT(RXC0))) ; + return UDR0; +#endif +} + +uint8_t serial_read_available() +{ +#ifdef SERIAL_ASYNC + return ringbuffer_fill(rx); +#else + return (UCSR0A&BIT(RXC0))!=0; +#endif +} + +uint8_t serial_read_overrun() +{ +#ifdef SERIAL_ASYNC + uint8_t o = rx_overrun; + rx_overrun = 0; + return o; +#else + return (UCSR0A&BIT(DOR0))!=0; +#endif } void serial_write(uint8_t c) { - while(!(UCSR0A&(1<