]> git.tdb.fi Git - model-railway-devices.git/commitdiff
Expand the serial API and add an asynchronous mode
authorMikko Rasa <tdb@tdb.fi>
Mon, 28 Oct 2013 19:10:47 +0000 (21:10 +0200)
committerMikko Rasa <tdb@tdb.fi>
Mon, 28 Oct 2013 19:10:47 +0000 (21:10 +0200)
This breaks any existing code using the API, since the callback macro
isn't available anymore.

common/serial.c
common/serial.h

index a5e5cae98ecae7dd5b7a9db2f1a94aeae70f0d35..8874c3e07545f1d4b52cd1e60df6c003b6da1d64 100644 (file)
@@ -1,8 +1,23 @@
+#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;
@@ -13,11 +28,74 @@ void serial_init(uint16_t baud)
        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
index 04ea50b198fc502c2d4812ddd370746bc2e6ae93..f5d59876114c29d01876e3cdedd96b4a83184452 100644 (file)
@@ -1,16 +1,13 @@
 #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