]> git.tdb.fi Git - model-railway-devices.git/blob - common/serial.c
Provide peak current since last read
[model-railway-devices.git] / common / serial.c
1 #include <avr/interrupt.h>
2 #include <avr/io.h>
3 #include "delay.h"
4 #include "ringbuffer.h"
5 #include "serial.h"
6
7 #define BIT(n) (1<<(n))
8
9 #ifndef SERIAL_BUFSIZE
10 #define SERIAL_BUFSIZE 16
11 #endif
12
13 #ifdef SERIAL_ASYNC
14 static RINGBUFFER(rx, SERIAL_BUFSIZE);
15 static RINGBUFFER(tx, SERIAL_BUFSIZE);
16 static uint8_t rx_overrun;
17 #define INTERRUPTS BIT(RXCIE0)
18 #else
19 #define INTERRUPTS 0
20 #endif
21
22 static inline void set_baud(uint16_t baud)
23 {
24         baud = (F_CPU/16+baud/2)/baud-1;
25         UBRR0H = baud>>8;
26         UBRR0L = baud;
27 }
28
29 void serial_init(uint16_t baud)
30 {
31         DDRD = (DDRD&~0x03) | 0x02;
32         PORTD &= ~0x03;
33
34         set_baud(baud);
35         UCSR0A = 0;
36         UCSR0C = BIT(UCSZ00) | BIT(UCSZ01);  // 8N1
37         UCSR0B = BIT(RXEN0) | BIT(TXEN0) | INTERRUPTS;
38 }
39
40 void serial_set_baud(uint16_t baud)
41 {
42 #ifdef SERIAL_ASYNC
43         while(!(UCSR0A&BIT(UDRE0))) ;
44 #endif
45         /* It's impossible to reliably find out when transmission has finished.
46         Wait for one character duration to be safe. */
47         uint16_t delay = (UBRR0H<<8)|UBRR0L;
48         for(uint8_t i=0; i<40; ++i)
49                 delay_loop16(delay);
50         set_baud(baud);
51 }
52
53 uint8_t serial_read()
54 {
55 #ifdef SERIAL_ASYNC
56         return ringbuffer_blocking_pop(rx);
57 #else
58         while(!(UCSR0A&BIT(RXC0))) ;
59         return UDR0;
60 #endif
61 }
62
63 uint8_t serial_read_available()
64 {
65 #ifdef SERIAL_ASYNC
66         return ringbuffer_fill(rx);
67 #else
68         return (UCSR0A&BIT(RXC0))!=0;
69 #endif
70 }
71
72 uint8_t serial_read_overrun()
73 {
74 #ifdef SERIAL_ASYNC
75         uint8_t o = rx_overrun;
76         rx_overrun = 0;
77         return o;
78 #else
79         return (UCSR0A&BIT(DOR0))!=0;
80 #endif
81 }
82
83 void serial_write(uint8_t c)
84 {
85 #ifdef SERIAL_ASYNC
86         ringbuffer_blocking_push(tx, c);
87         UCSR0B |= BIT(UDRIE0);
88 #else
89         while(!(UCSR0A&BIT(UDRE0))) ;
90         UDR0 = c;
91 #endif
92 }
93
94 uint8_t serial_write_space()
95 {
96 #ifdef SERIAL_ASYNC
97         return ringbuffer_space(tx);
98 #else
99         return (UCSR0A&BIT(UDRE0))!=0;
100 #endif
101 }
102
103 #ifdef SERIAL_ASYNC
104 ISR(USART_UDRE_vect)
105 {
106         if(ringbuffer_fill(tx))
107                 UDR0 = ringbuffer_pop(tx);
108         else
109                 UCSR0B &= ~BIT(UDRIE0);
110 }
111
112 ISR(USART_RX_vect)
113 {
114         uint8_t c = UDR0;
115         if(!ringbuffer_space(rx))
116                 rx_overrun = 1;
117         else
118                 ringbuffer_push(rx, c);
119 }
120 #endif