]> git.tdb.fi Git - model-railway-devices.git/blob - common/serial.c
Expand the serial API and add an asynchronous mode
[model-railway-devices.git] / common / serial.c
1 #include <avr/interrupt.h>
2 #include <avr/io.h>
3 #include "ringbuffer.h"
4 #include "serial.h"
5
6 #define BIT(n) (1<<(n))
7
8 #ifndef SERIAL_BUFSIZE
9 #define SERIAL_BUFSIZE 16
10 #endif
11
12 #ifdef SERIAL_ASYNC
13 static RINGBUFFER(rx, SERIAL_BUFSIZE);
14 static RINGBUFFER(tx, SERIAL_BUFSIZE);
15 static uint8_t rx_overrun;
16 #define INTERRUPTS BIT(RXCIE0)
17 #else
18 #define INTERRUPTS 0
19 #endif
20
21 void serial_init(uint16_t baud)
22 {
23         DDRD = (DDRD&~0x03) | 0x02;
24         PORTD &= ~0x03;
25
26         baud = (F_CPU/16+baud/2)/baud-1;
27         UBRR0H = baud>>8;
28         UBRR0L = baud;
29         UCSR0A = 0;
30         UCSR0C = BIT(UCSZ00) | BIT(UCSZ01);  // 8N1
31         UCSR0B = BIT(RXEN0) | BIT(TXEN0) | INTERRUPTS;
32 }
33
34 uint8_t serial_read()
35 {
36 #ifdef SERIAL_ASYNC
37         return ringbuffer_blocking_pop(rx);
38 #else
39         while(!(UCSR0A&BIT(RXC0))) ;
40         return UDR0;
41 #endif
42 }
43
44 uint8_t serial_read_available()
45 {
46 #ifdef SERIAL_ASYNC
47         return ringbuffer_fill(rx);
48 #else
49         return (UCSR0A&BIT(RXC0))!=0;
50 #endif
51 }
52
53 uint8_t serial_read_overrun()
54 {
55 #ifdef SERIAL_ASYNC
56         uint8_t o = rx_overrun;
57         rx_overrun = 0;
58         return o;
59 #else
60         return (UCSR0A&BIT(DOR0))!=0;
61 #endif
62 }
63
64 void serial_write(uint8_t c)
65 {
66 #ifdef SERIAL_ASYNC
67         ringbuffer_blocking_push(tx, c);
68         UCSR0B |= BIT(UDRIE0);
69 #else
70         while(!(UCSR0A&BIT(UDRE0))) ;
71         UDR0 = c;
72 #endif
73 }
74
75 uint8_t serial_write_space()
76 {
77 #ifdef SERIAL_ASYNC
78         return ringbuffer_space(tx);
79 #else
80         return (UCSR0A&BIT(UDRE0))!=0;
81 #endif
82 }
83
84 #ifdef SERIAL_ASYNC
85 ISR(USART_UDRE_vect)
86 {
87         if(ringbuffer_fill(tx))
88                 UDR0 = ringbuffer_pop(tx);
89         else
90                 UCSR0B &= ~BIT(UDRIE0);
91 }
92
93 ISR(USART_RX_vect)
94 {
95         uint8_t c = UDR0;
96         if(!ringbuffer_space(rx))
97                 rx_overrun = 1;
98         else
99                 ringbuffer_push(rx, c);
100 }
101 #endif