]> www.fi.muni.cz Git - openparking.git/blob - firmware/rs485.c
7aec92c8e54a4abf1f31691b411e44a5aac4a167
[openparking.git] / firmware / rs485.c
1 /*
2  * Loosely modelled after AVR-RS485 by Yoshinori Kohyama (http://algobit.jp/),
3  * available at https://github.com/kohyama/AVR-RS485/
4  *
5  * All bugs by Jan "Yenya" Kasprzak <kas@fi.muni.cz> :-)
6  */
7
8 #include <avr/io.h>
9 #include <avr/interrupt.h>
10 #include <util/delay.h>
11
12 #define BUFSIZE 128     // must be a power of two
13
14 // configure the control pin
15 #define ctl_pin_setup() do { DDRD  |=  _BV(PD2); } while (0)
16 #define ctl_pin_on()    do { PORTD |=  _BV(PD2); } while (0)
17 #define ctl_pin_off()   do { PORTD &= ~_BV(PD2); } while (0)
18
19 #define BUFMASK (BUFSIZE-1)
20 #if (BUFSIZE & BUFMASK)
21 #error BUFSIZE must be a power of two
22 #endif
23
24 #if BUFSIZE > 255
25 typedef uint16_t bufptr_t;
26 #else
27 typedef uint8_t  bufptr_t;
28 #endif
29
30 #define bufptr_inc(x)   ((x + 1) & BUFMASK)
31
32 static volatile bufptr_t rx_head, rx_tail, tx_head, tx_tail;
33 static volatile char rxbuf[BUFSIZE], txbuf[BUFSIZE];
34
35 #define UART_BAUD       9600
36 #define UBRR_VAL        ((F_CPU + 8UL * UART_BAUD) / (16UL*UART_BAUD) - 1)
37
38 void rs485_init()
39 {
40         rx_head = rx_tail = 0;
41         tx_head = tx_tail = 0;
42
43         ctl_pin_off();
44         ctl_pin_setup();
45
46         UBRR0 = UBRR_VAL;
47         UCSR0A = 0;
48         UCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);
49         UCSR0C = _BV(UCSZ01)|_BV(UCSZ00);
50 }
51
52 void rs485_send(char *p)
53 {
54         bufptr_t next;
55
56         if (*p == '\0')
57                 return;
58
59         cli();
60
61         next = bufptr_inc(tx_head);
62         while (next != tx_tail && *p != '\0') {
63                 txbuf[tx_head] = *p++;
64                 tx_head = next;
65                 next = bufptr_inc(tx_head);
66         }
67         ctl_pin_on();
68         UCSR0B |= _BV(UDRIE0);
69         sei();
70 }
71
72 bufptr_t rs485_readln(char *buf, bufptr_t size)
73 {
74         int n = 0;
75
76         do {
77                 cli();
78                 while (rx_head != rx_tail && n + 1 < size) {
79                         buf[n++] = rxbuf[rx_tail];
80                         rx_tail = bufptr_inc(rx_tail);
81                 }
82                 sei();
83         } while (n == 0 || buf[n - 1] != 0x0a);
84         buf[n] = '\0';
85
86         return n;
87 }
88
89 ISR(USART_RX_vect)
90 {
91         bufptr_t next;
92
93         cli();
94         next = bufptr_inc(rx_head);
95         rxbuf[rx_head] = UDR0;
96         if (next != rx_tail)
97                 rx_head = next;
98         sei();
99 }
100
101 ISR(USART_TX_vect)
102 {
103         UCSR0B &= ~_BV(TXCIE0); // disable further IRQs
104         ctl_pin_off();
105 }
106
107 ISR(USART_UDRE_vect)
108 {
109         cli();
110         if (tx_head == tx_tail) {
111                 UCSR0B |= _BV(TXCIE0); // enable xmit complete irq
112                 UCSR0B &= ~_BV(UDRIE0);
113         } else {
114                 UDR0 = txbuf[tx_tail];
115                 tx_tail = bufptr_inc(tx_tail);
116         }
117         sei();
118 }