+#include <avr/interrupt.h>
#include <avr/io.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
+
void serial_init(uint16_t baud)
{
DDRD = (DDRD&~0x03) | 0x02;
UBRR0L = baud;
UCSR0A = 0;
UCSR0C = BIT(UCSZ00) | BIT(UCSZ01); // 8N1
- UCSR0B = BIT(RXEN0) | BIT(TXEN0) | BIT(RXCIE0);
+ UCSR0B = BIT(RXEN0) | BIT(TXEN0) | INTERRUPTS;
+}
+
+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<<UDRE0))) ;
+#ifdef SERIAL_ASYNC
+ ringbuffer_blocking_push(tx, c);
+ UCSR0B |= BIT(UDRIE0);
+#else
+ while(!(UCSR0A&BIT(UDRE0))) ;
UDR0 = c;
+#endif
+}
+
+uint8_t serial_write_space()
+{
+#ifdef SERIAL_ASYNC
+ return ringbuffer_space(tx);
+#else
+ return (UCSR0A&BIT(UDRE0))!=0;
+#endif
+}
+
+#ifdef SERIAL_ASYNC
+ISR(USART_UDRE_vect)
+{
+ if(ringbuffer_fill(tx))
+ UDR0 = ringbuffer_pop(tx);
+ else
+ UCSR0B &= ~BIT(UDRIE0);
+}
+
+ISR(USART_RX_vect)
+{
+ uint8_t c = UDR0;
+ if(!ringbuffer_space(rx))
+ rx_overrun = 1;
+ else
+ ringbuffer_push(rx, c);
}
+#endif
#ifndef SERIAL_H_
#define SERIAL_H_
-#include <avr/interrupt.h>
-
-#define SERIAL_SET_CALLBACK(f) \
- ISR(USART_RX_vect) \
- { \
- char c = UDR0; \
- f(c); \
- }
+#include <stdint.h>
void serial_init(uint16_t);
+uint8_t serial_read();
+uint8_t serial_read_available();
+uint8_t serial_read_overrun();
void serial_write(uint8_t);
+uint8_t serial_write_space();
#endif