-
Notifications
You must be signed in to change notification settings - Fork 0
/
usart0.c
254 lines (209 loc) · 5.54 KB
/
usart0.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#include <stdio.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include <config.h>
#include <usart0.h>
#include <events.h>
typedef struct
{
uint8_t au8RXLineBuffer[UART_RX_LINE_BUFFER];
volatile uint8_t u8NextWritePos;
} RXB;
static RXB stRXB;
//static FILE USART0_stream = FDEV_SETUP_STREAM (USART0_iSendByteToStream, NULL, _FDEV_SETUP_WRITE);
static FILE USART0_stream = FDEV_SETUP_STREAM (USART0_iSendByteToStream, USART0_iReceiveByteForStream, _FDEV_SETUP_RW);
/**
* Enable receiver and receive complete interrupt
*/
void USART0_vRXEnable(void)
{
UCSR0B |= ( _BV(RXEN0) | _BV(RXCIE0) );
}
void USART0_RXDisable(void)
{
UCSR0B &= ~ ( _BV(RXEN0) | _BV(RXCIE0) );
}
/**
*
* @param USART_RX_vect
*/
ISR(USART_RX_vect)
{
// Due to the buffering of the Error
// Flags, the UCSRnA must be read before the receive buffer (UDRn)
uint8_t u8Status = UCSR0A;
// reading UDR clears interrupt flag
uint8_t u8Char = UDR0;
if ( u8Status & (_BV(FE0) |_BV(DOR0) | _BV(UPE0)) )
{
// ignore bad frames
return;
}
switch (u8Char)
{
case 0x7F: // backspace
if (stRXB.u8NextWritePos > 0)
{
stRXB.u8NextWritePos--;
USART0_iSendByteToStream(u8Char, NULL); // TODO: make TX buffered and interrupt driven
}
return; // ignore character (even do not echo)
break;
//TODO ignore escaped sequences like arrows
// case '\r':
// break;
//
// default:
// if (u8Char>126)
// return; // ignore character (even do not echo)
// if (u8Char<32)
// return; // ignore character (even do not echo)
// break;
}
#if (1) // echo enabled
//if (stRXB.u8NextWritePos > 0)
{
USART0_iSendByteToStream(u8Char, NULL); // TODO: make TX buffered and interrupt driven
//USART0_vSendByte (u8Char);
}
#endif
// do not store \r into line buffer
// check end of line, before storing it into buffer
if (u8Char == '\r')
{
USART0_RXDisable();
stRXB.au8RXLineBuffer[stRXB.u8NextWritePos] = 0; // null terminator
EventPostFromIRQ(EV_UART_LINE_COMPLETE);
return;
}
// write if there is space in buffer
if (stRXB.u8NextWritePos < sizeof(stRXB.au8RXLineBuffer))
{
stRXB.au8RXLineBuffer[stRXB.u8NextWritePos] = u8Char;
stRXB.u8NextWritePos++;
}
else
{
USART0_RXDisable();
EventPostFromIRQ(EV_UART_LINE_FULL);
return;
}
}
void USART0_vInit(void)
{
#undef BAUD
#define BAUD (USART0_BAUD)
// baud tolerance in percent
// 115200 with CLK 16MHz gives 3% error
#define BAUD_TOL 3 // baud tolerance in percent
#include <util/setbaud.h>
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= _BV(U2X0);
#endif
// Set baud rate
//UBRR0H = (unsigned char) (USART0_UBBR_VAL >>8 );
//UBRR0L = (unsigned char) (USART0_UBBR_VAL);
// Enable transmitter
UCSR0B = (
0 /*_BV(RXEN0)*/
| _BV(TXEN0)
/*| _BV(RXCIE0)*/
);
// set asynchronous mode, 8 bit data, NO parity, 1 bit stop
UCSR0C = (
_BV(UCSZ01) | _BV(UCSZ00) // 8 bit
);
stdin = stderr = stdout = &USART0_stream;
}
/**
* Wait for TX buffer empty
*/
void USART0_vFlush(void)
{
loop_until_bit_is_set (UCSR0A, UDRE0); // wait for empty buffer
//ATMEL: The TXCn Flag can be used to check that the Transmitter has completed all transfers
// Note that the TXCn Flag must be cleared before each transmission (before UDRn is written) if it is used for this purpose
//loop_until_bit_is_clear (UCSR0A, TXC0); // wait for TX complete flag
_delay_ms(1);
}
void USART0_vRXFlush(void)
{
uint8_t u8Char;
while ( UCSR0A & (1<<RXC0) )
u8Char = UDR0;
(void)u8Char;
}
/**
* Transmit single character
* @param ucByte
*/
void USART0_vSendByte (unsigned char ucByte)
{
// wait for data registry empty
loop_until_bit_is_set (UCSR0A, UDRE0);
//ATMEL: Note that the TXCn Flag must be cleared before each transmission (before UDRn is written) if it is used for this purpose
UCSR0A |= _BV(TXC0); // clear TXC0 by writing 1
UDR0 = ucByte;
//loop_until_bit_is_set(UCSR0A, TXC0);
}
int USART0_iSendByteToStream (unsigned char ucByte, FILE *stream)
{
// implicit CR on every NL
if (ucByte == '\n')
{
USART0_vSendByte ('\r');
}
if (ucByte == '\r')
{
USART0_vSendByte ('\n');
}
USART0_vSendByte (ucByte);
return 1;
}
BOOL USART0_bIsByteAvail(void)
{
return (UCSR0A & _BV(RXC0));
}
/**
* Blocking!
* @return
*/
unsigned char USART0_ucGetByte(void)
{
// wait for data
//loop_until_bit_is_set (UCSR0A, RXC0);
while ( ! (UCSR0A & _BV(RXC0)) )
{
wdt_reset(); // Shity solution, but Timer0 is still counting GUI time out
}
return UDR0;
}
/**
* Blocking!
* @param stream
* @return
*/
int USART0_iReceiveByteForStream (FILE *stream)
{
uint8_t u8Byte = USART0_ucGetByte();
USART0_iSendByteToStream(u8Byte, stream); // echo characters
return u8Byte;
}
uint8_t * pu8GetLineBuf(void)
{
return stRXB.au8RXLineBuffer;
}
void USART0_vRXWaitForLine(void)
{
stRXB.u8NextWritePos = 0;
memset (stRXB.au8RXLineBuffer, 0, UART_RX_LINE_BUFFER );
USART0_vRXFlush();
USART0_vRXEnable();
}