forked from sparkfun/OpenLog
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSerialPort.cpp
268 lines (264 loc) · 7.46 KB
/
SerialPort.cpp
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/* Arduino SerialPort Library
* Copyright (C) 2011 by William Greiman
*
* This file is part of the Arduino SerialPort Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SerialPort Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SerialPort.h>
//------------------------------------------------------------------------------
/** \return the number of bytes in the ring buffer */
int SerialRingBuffer::available() {
uint8_t s = SREG;
cli();
int n = head_ - tail_;
SREG = s;
return n < 0 ? size_ + n : n;
}
//------------------------------------------------------------------------------
/** Discard all data in the ring buffer. */
void SerialRingBuffer::flush() {
uint8_t s = SREG;
cli();
head_ = tail_ = 0;
SREG = s;
}
//------------------------------------------------------------------------------
/** get the next byte
* \param[in] b location for the returned byte
* \return true if a byte was returned or false if the ring buffer is empty
*/
bool SerialRingBuffer::get(uint8_t* b) {
buf_size_t t = tail_;
if (head_ == t) return false;
*b = buf_[t++];
tail_ = t < size_ ? t : 0;
return true;
}
//------------------------------------------------------------------------------
/**
* Get the maximum number of contiguous bytes from the ring buffer
* with one call to memcpy. Do not use this function with interrupts
* disabled.
*
* \param[in] b pointer to data
* \param[in] n number of bytes to transfer from the ring buffer
* \return number of bytes transferred
*/
SerialRingBuffer::buf_size_t SerialRingBuffer::get(uint8_t* b, buf_size_t n) {
buf_size_t nr;
cli();
buf_size_t h = head_;
sei();
buf_size_t t = tail_;
if (h < t) {
nr = size_ - t;
} else if (t < h) {
nr = h - t;
} else {
return 0;
}
if (nr > n) nr = n;
memcpy(b, &buf_[t], nr);
t += nr;
tail_ = t < size_ ? t : t - size_;
return nr;
}
//------------------------------------------------------------------------------
/** initialize the ring buffer
* \param[in] b buffer for data
* \param[in] s size of the buffer
*/
void SerialRingBuffer::init(uint8_t* b, buf_size_t s) {
buf_ = b;
size_ = s;
head_ = tail_ = 0;
}
//------------------------------------------------------------------------------
/** peek at the next byte in the ring buffer
* \return the next byte that would ber read or -1 if the ring buffer is empty
*/
int SerialRingBuffer::peek() {
return empty() ? -1 : buf_[tail_];
}
//------------------------------------------------------------------------------
/** put a byte into the ring buffer
* \param[in] b the byte
* \return true if byte was transferred or false if the ring buffer is full
*/
bool SerialRingBuffer::put(uint8_t b) {
buf_size_t h = head_;
// OK to store here even if ring is full
buf_[h++] = b;
if (h >= size_) h = 0;
if (h == tail_) return false;
head_ = h;
return true;
}
//------------------------------------------------------------------------------
/**
* Put the maximum number of contiguous bytes into the ring buffer
* with one call to memcpy.
*
* \param[in] b pointer to data
* \param[in] n number of bytes to transfer to the ring buffer
* \return number of bytes transferred
*/
SerialRingBuffer::buf_size_t
SerialRingBuffer::put(const uint8_t* b, buf_size_t n) {
cli();
buf_size_t t = tail_;
sei();
buf_size_t space; // space in ring buffer
buf_size_t h = head_;
if (h < t) {
space = t - h - 1;
} else {
space = size_ - h;
if (t == 0) space -= 1;
}
if (n > space) n = space;
memcpy(&buf_[h], b, n);
h += n;
head_ = h < size_ ? h : h - size_;
return n;
}
//------------------------------------------------------------------------------
/**
* Put the maximum number of contiguous bytes into the ring buffer
* with one call to memcpy.
*
* \param[in] b pointer to data
* \param[in] n number of bytes to transfer to the ring buffer
* \return number of bytes transferred
*/
SerialRingBuffer::buf_size_t SerialRingBuffer::put_P(PGM_P b, buf_size_t n) {
cli();
buf_size_t t = tail_;
sei();
buf_size_t space; // space in ring buffer
buf_size_t h = head_;
if (h < t) {
space = t - h - 1;
} else {
space = size_ - h;
if (t == 0) space -= 1;
}
if (n > space) n = space;
memcpy_P(&buf_[h], b, n);
h += n;
head_ = h < size_ ? h : h - size_;
return n;
}
//==============================================================================
// global data and ISRs
#if ENABLE_RX_ERROR_CHECKING
//
uint8_t rxErrorBits[SERIAL_PORT_COUNT];
#endif // ENABLE_RX_ERROR_CHECKING
//------------------------------------------------------------------------------
#if BUFFERED_RX
//------------------------------------------------------------------------------
SerialRingBuffer rxRingBuf[SERIAL_PORT_COUNT];
//------------------------------------------------------------------------------
#if ENABLE_RX_ERROR_CHECKING
inline static void rx_isr(uint8_t n) {
uint8_t e = *usart[n].ucsra & SP_UCSRA_ERROR_MASK;
uint8_t b = *usart[n].udr;
if (!rxRingBuf[n].put(b)) e |= SP_RX_BUF_OVERRUN;
rxErrorBits[n] |= e;
}
#else // ENABLE_RX_ERROR_CHECKING
inline static void rx_isr(uint8_t n) {
uint8_t b = *usart[n].udr;
rxRingBuf[n].put(b);
}
#endif // ENABLE_RX_ERROR_CHECKING
//------------------------------------------------------------------------------
// SerialRingBuffer rxbuf0;
#if defined(USART_RX_vect)
ISR(USART_RX_vect) {
#elif defined(SIG_USART0_RECV)
ISR(SIG_USART0_RECV) {
#elif defined(SIG_UART0_RECV)
ISR(SIG_UART0_RECV) {
#elif defined(USART0_RX_vect)
ISR(USART0_RX_vect) {
#elif defined(SIG_UART_RECV)
ISR(SIG_UART_RECV) {
#else // vector
#error No ISR rx vector for UART0
#endif // vector
rx_isr(0);
}
#ifdef USART1_RX_vect
ISR(USART1_RX_vect) {
rx_isr(1);
}
#endif // USART1_RX_vect
#ifdef USART2_RX_vect
ISR(USART2_RX_vect) {
rx_isr(2);
}
#endif // USART2_RX_vect
#ifdef USART3_RX_vect
ISR(USART3_RX_vect) {
rx_isr(3);
}
#endif // USART3_RX_vect
#endif // BUFFERED_RX
//------------------------------------------------------------------------------
#if BUFFERED_TX
//------------------------------------------------------------------------------
SerialRingBuffer txRingBuf[SERIAL_PORT_COUNT];
//------------------------------------------------------------------------------
inline static void tx_isr(uint8_t n) {
uint8_t b;
if (txRingBuf[n].get(&b)) {
*usart[n].udr = b;
} else {
// no data - disable interrupts
*usart[n].ucsrb &= ~M_UDRIE;
}
}
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect) {
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect) {
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect) {
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect) {
#else
#error N0 ISR tx vector for UART0
#endif
tx_isr(0);
}
#ifdef USART1_UDRE_vect
ISR(USART1_UDRE_vect) {
tx_isr(1);
}
#endif // USART1_UDRE_vect
#ifdef USART2_UDRE_vect
ISR(USART2_UDRE_vect) {
tx_isr(2);
}
#endif // USART2_UDRE_vect
#ifdef USART3_UDRE_vect
ISR(USART3_UDRE_vect) {
tx_isr(3);
}
#endif // USART3_UDRE_vect
#endif // BUFFERED_TX