]> www.fi.muni.cz Git - openparking.git/blob - firmware/rs485.c
Directory layout
[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 #define wait_one_byte() _delay_us(10*1000000/UART_BAUD)
38
39 void rs485_init()
40 {
41         rx_head = rx_tail = 0;
42         tx_head = tx_tail = 0;
43
44         ctl_pin_off();
45         ctl_pin_setup();
46
47         UBRR0 = UBRR_VAL;
48         UCSR0A = 0;
49         UCSR0B = _BV(RXCIE0)|_BV(RXEN0)|_BV(TXEN0);
50         UCSR0C = _BV(UCSZ01)|_BV(UCSZ00);
51 }
52
53 void rs485_send(char *p)
54 {
55         bufptr_t next;
56
57         if (*p == '\0')
58                 return;
59
60         cli();
61
62         next = bufptr_inc(tx_head);
63         while (next != tx_tail && *p != '\0') {
64                 txbuf[tx_head] = *p++;
65                 tx_head = next;
66                 next = bufptr_inc(tx_head);
67         }
68         ctl_pin_on();
69         UCSR0B |= _BV(UDRIE0);
70         sei();
71 }
72
73 bufptr_t rs485_readln(char *buf, bufptr_t size)
74 {
75         int n = 0;
76
77         do {
78                 cli();
79                 while (rx_head != rx_tail && n + 1 < size) {
80                         buf[n++] = rxbuf[rx_tail];
81                         rx_tail = bufptr_inc(rx_tail);
82                 }
83                 sei();
84         } while (n == 0 || buf[n - 1] != 0x0a);
85         buf[n] = '\0';
86
87         return n;
88 }
89
90 ISR(USART_RX_vect)
91 {
92         bufptr_t next;
93
94         cli();
95         next = bufptr_inc(rx_head);
96         rxbuf[rx_head] = UDR0;
97         if (next != rx_tail)
98                 rx_head = next;
99         sei();
100 }
101
102 ISR(USART_UDRE_vect)
103 {
104         cli();
105         if (tx_head == tx_tail) {
106                 UCSR0B &= ~_BV(UDRIE0);
107                 wait_one_byte();
108                 ctl_pin_off();
109         } else {
110                 UDR0 = txbuf[tx_tail];
111                 tx_tail = bufptr_inc(tx_tail);
112         }
113         sei();
114 }