Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1702 - 1
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-
2
//
3
// Interrupt-driven serial transmit/receive library.
4
//
5
//      Copyright (c) 2010 Michael Smith. All rights reserved.
6
//
7
// Receive and baudrate calculations derived from the Arduino
8
// HardwareSerial driver:
9
//
10
//      Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
11
//
12
// Transmit algorithm inspired by work:
13
//
14
//      Code Jose Julio and Jordi Munoz. DIYDrones.com
15
//
16
//      This library is free software; you can redistribute it and/or
17
//      modify it under the terms of the GNU Lesser General Public
18
//      License as published by the Free Software Foundation; either
19
//      version 2.1 of the License, or (at your option) any later
20
//      version.
21
//
22
//      This library is distributed in the hope that it will be
23
//      useful, but WITHOUT ANY WARRANTY; without even the implied
24
//      warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
25
//      PURPOSE.  See the GNU Lesser General Public License for more
26
//      details.
27
//
28
//      You should have received a copy of the GNU Lesser General
29
//      Public License along with this library; if not, write to the
30
//      Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
31
//      Boston, MA 02110-1301 USA
32
//
33
 
34
//
35
// Note that this library does not pre-declare drivers for serial
36
// ports; the user must explicitly create drivers for the ports they
37
// wish to use.  This is less friendly than the stock Arduino driver,
38
// but it saves a few bytes of RAM for every unused port and frees up
39
// the vector for another driver (e.g. MSPIM on USARTs).
40
//
41
 
42
#ifndef FastSerial_h
43
#define FastSerial_h
44
 
45
// disable the stock Arduino serial driver
46
#ifdef HardwareSerial_h
47
# error Must include FastSerial.h before the Arduino serial driver is defined.
48
#endif
49
#define HardwareSerial_h
50
 
51
#include <inttypes.h>
52
#include <stdlib.h>
53
#include <avr/io.h>
54
#include <avr/interrupt.h>
55
 
56
#include "BetterStream.h"
57
 
58
 
59
/// @file       FastSerial.h
60
/// @brief      An enhanced version of the Arduino HardwareSerial class
61
///                     implementing interrupt-driven transmission and flexible
62
///                     buffer management.
63
///
64
/// Because Arduino libraries aren't really libraries, but we want to
65
/// only define interrupt handlers for serial ports that are actually
66
/// used, we have to force our users to define them using a macro.
67
///
68
/// FastSerialPort(<port name>, <port number>)
69
///
70
/// <port name> is the name of the object that will be created by the
71
/// macro.  <port number> is the 0-based number of the port that will
72
/// be managed by the object.
73
///
74
/// Previously ports were defined with a different macro for each port,
75
/// and these macros are retained for compatibility:
76
///
77
/// FastSerialPort0(<port name>)         creates <port name> referencing serial port 0
78
/// FastSerialPort1(<port name>)         creates <port name> referencing serial port 1
79
/// FastSerialPort2(<port name>)         creates <port name> referencing serial port 2
80
/// FastSerialPort3(<port name>)         creates <port name> referencing serial port 3
81
///
82
/// Note that compatibility macros are only defined for ports that
83
/// exist on the target device.
84
///
85
 
86
///     @name   Compatibility
87
///
88
/// Forward declarations for clients that want to assume that the
89
/// default Serial* objects exist.
90
///
91
/// Note that the application is responsible for ensuring that these
92
/// actually get defined, otherwise Arduino will suck in the
93
/// HardwareSerial library and linking will fail.
94
//@{
95
extern class FastSerial Serial;
96
extern class FastSerial Serial1;
97
extern class FastSerial Serial2;
98
extern class FastSerial Serial3;
99
//@}
100
 
101
/// The FastSerial class definition
102
///
103
class FastSerial: public BetterStream {
104
public:
105
 
106
        /// Constructor
107
        FastSerial(const uint8_t portNumber, volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, volatile uint8_t *ucsra,
108
                           volatile uint8_t *ucsrb, const uint8_t u2x, const uint8_t portEnableBits, const uint8_t portTxBits);
109
 
110
        /// @name       Serial API
111
        //@{
112
        virtual void begin(long baud);
113
        virtual void end(void);
114
        virtual int available(void);
115
        virtual int txspace(void);
116
        virtual int read(void);
117
        virtual int peek(void);
118
        virtual void flush(void);
119
#if defined(ARDUINO) && ARDUINO >= 100
120
        virtual size_t write(uint8_t c);
121
#else
122
        virtual void write(uint8_t c);
123
#endif
124
        using BetterStream::write;
125
        //@}
126
 
127
        /// Extended port open method
128
        ///
129
        /// Allows for both opening with specified buffer sizes, and re-opening
130
        /// to adjust a subset of the port's settings.
131
        ///
132
        /// @note       Buffer sizes greater than ::_max_buffer_size will be rounded
133
        ///                     down.
134
        ///
135
        /// @param      baud            Selects the speed that the port will be
136
        ///                                             configured to.  If zero, the port speed is left
137
        ///                                             unchanged.
138
        /// @param rxSpace              Sets the receive buffer size for the port.  If zero
139
        ///                                             then the buffer size is left unchanged if the port
140
        ///                                             is open, or set to ::_default_rx_buffer_size if it is
141
        ///                                             currently closed.
142
        /// @param txSpace              Sets the transmit buffer size for the port.  If zero
143
        ///                                             then the buffer size is left unchanged if the port
144
        ///                                             is open, or set to ::_default_tx_buffer_size if it
145
        ///                                             is currently closed.
146
        ///
147
        virtual void begin(long baud, unsigned int rxSpace, unsigned int txSpace);
148
 
149
        /// Transmit/receive buffer descriptor.
150
        ///
151
        /// Public so the interrupt handlers can see it
152
        struct Buffer {
153
                volatile uint16_t head, tail;   ///< head and tail pointers
154
                uint16_t mask;                                  ///< buffer size mask for pointer wrap
155
                uint8_t *bytes;                                 ///< pointer to allocated buffer
156
        };
157
 
158
        /// Tell if the serial port has been initialized
159
        static bool getInitialized(uint8_t port) {
160
                return (1<<port) & _serialInitialized;
161
        }
162
 
163
        // ask for writes to be blocking or non-blocking
164
        void set_blocking_writes(bool blocking) {
165
                _nonblocking_writes = !blocking;
166
        }
167
 
168
private:
169
 
170
        /// Bit mask for initialized ports
171
        static uint8_t _serialInitialized;
172
 
173
        /// Set if the serial port has been initialized
174
        static void setInitialized(uint8_t port) {
175
                _serialInitialized |= (1<<port);
176
        }
177
 
178
        // register accessors
179
        volatile uint8_t * const _ubrrh;
180
        volatile uint8_t * const _ubrrl;
181
        volatile uint8_t * const _ucsra;
182
        volatile uint8_t * const _ucsrb;
183
 
184
        // register magic numbers
185
        const uint8_t   _u2x;
186
        const uint8_t   _portEnableBits;                ///< rx, tx and rx interrupt enables
187
        const uint8_t   _portTxBits;                    ///< tx data and completion interrupt enables
188
 
189
 
190
        // ring buffers
191
        Buffer                  * const _rxBuffer;
192
        Buffer                  * const _txBuffer;
193
        bool                    _open;
194
 
195
        // whether writes to the port should block waiting
196
        // for enough space to appear
197
        bool                    _nonblocking_writes;
198
 
199
        /// Allocates a buffer of the given size
200
        ///
201
        /// @param      buffer          The buffer descriptor for which the buffer will
202
        ///                                             will be allocated.
203
        /// @param      size            The desired buffer size.
204
        /// @returns                    True if the buffer was allocated successfully.
205
        ///
206
        static bool _allocBuffer(Buffer *buffer, unsigned int size);
207
 
208
        /// Frees the allocated buffer in a descriptor
209
        ///
210
        /// @param      buffer          The descriptor whose buffer should be freed.
211
        ///
212
        static void _freeBuffer(Buffer *buffer);
213
 
214
        /// default receive buffer size
215
        static const unsigned int       _default_rx_buffer_size = 128;
216
 
217
        /// default transmit buffer size
218
        static const unsigned int       _default_tx_buffer_size = 16;
219
 
220
        /// maxium tx/rx buffer size
221
        /// @note if we could bring the max size down to 256, the mask and head/tail
222
        ///       pointers in the buffer could become uint8_t.
223
        ///
224
        static const unsigned int       _max_buffer_size = 512;
225
};
226
 
227
// Used by the per-port interrupt vectors
228
extern FastSerial::Buffer __FastSerial__rxBuffer[];
229
extern FastSerial::Buffer __FastSerial__txBuffer[];
230
 
231
/// Generic Rx/Tx vectors for a serial port - needs to know magic numbers
232
///
233
#define FastSerialHandler(_PORT, _RXVECTOR, _TXVECTOR, _UDR, _UCSRB, _TXBITS) \
234
ISR(_RXVECTOR, ISR_BLOCK)                                               \
235
{                                                                       \
236
        uint8_t c;                                                      \
237
        uint16_t i;                                                      \
238
                                                                        \
239
        /* read the byte as quickly as possible */                      \
240
        c = _UDR;                                                       \
241
        /* work out where the head will go next */                      \
242
        i = (__FastSerial__rxBuffer[_PORT].head + 1) & __FastSerial__rxBuffer[_PORT].mask; \
243
        /* decide whether we have space for another byte */             \
244
        if (i != __FastSerial__rxBuffer[_PORT].tail) {                  \
245
                /* we do, move the head */                              \
246
                __FastSerial__rxBuffer[_PORT].bytes[__FastSerial__rxBuffer[_PORT].head] = c; \
247
                __FastSerial__rxBuffer[_PORT].head = i;                 \
248
        }                                                               \
249
}                                                                       \
250
ISR(_TXVECTOR, ISR_BLOCK)                                               \
251
{                                                                       \
252
        /* if there is another character to send */                     \
253
        if (__FastSerial__txBuffer[_PORT].tail != __FastSerial__txBuffer[_PORT].head) { \
254
                _UDR = __FastSerial__txBuffer[_PORT].bytes[__FastSerial__txBuffer[_PORT].tail]; \
255
                /* increment the tail */                                \
256
                __FastSerial__txBuffer[_PORT].tail =                    \
257
                        (__FastSerial__txBuffer[_PORT].tail + 1) & __FastSerial__txBuffer[_PORT].mask; \
258
        } else {                                                        \
259
                /* there are no more bytes to send, disable the interrupt */ \
260
                if (__FastSerial__txBuffer[_PORT].head == __FastSerial__txBuffer[_PORT].tail) \
261
                        _UCSRB &= ~_TXBITS;                             \
262
        }                                                               \
263
}                                                                       \
264
struct hack
265
 
266
//
267
// Portability; convert various older sets of defines for U(S)ART0 up
268
// to match the definitions for the 1280 and later devices.
269
//
270
#if !defined(USART0_RX_vect)
271
# if defined(USART_RX_vect)
272
#  define USART0_RX_vect        USART_RX_vect
273
#  define USART0_UDRE_vect      USART_UDRE_vect
274
# elif defined(UART0_RX_vect)
275
#  define USART0_RX_vect        UART0_RX_vect
276
#  define USART0_UDRE_vect      UART0_UDRE_vect
277
# endif
278
#endif
279
 
280
#if !defined(USART1_RX_vect)
281
# if defined(UART1_RX_vect)
282
#  define USART1_RX_vect        UART1_RX_vect
283
#  define USART1_UDRE_vect      UART1_UDRE_vect
284
# endif
285
#endif
286
 
287
#if !defined(UDR0)
288
# if defined(UDR)
289
#  define UDR0                  UDR
290
#  define UBRR0H                UBRRH
291
#  define UBRR0L                UBRRL
292
#  define UCSR0A                UCSRA
293
#  define UCSR0B                UCSRB
294
#  define U2X0                  U2X
295
#  define RXEN0                 RXEN
296
#  define TXEN0                 TXEN
297
#  define RXCIE0                RXCIE
298
#  define UDRIE0                UDRIE
299
# endif
300
#endif
301
 
302
///
303
/// Macro defining a FastSerial port instance.
304
///
305
#define FastSerialPort(_name, _num)                                     \
306
        FastSerial _name(_num,                                          \
307
                         &UBRR##_num##H,                                \
308
                         &UBRR##_num##L,                                \
309
                         &UCSR##_num##A,                                \
310
                         &UCSR##_num##B,                                \
311
                         U2X##_num,                                     \
312
                         (_BV(RXEN##_num) |  _BV(TXEN##_num) | _BV(RXCIE##_num)), \
313
                         (_BV(UDRIE##_num)));                           \
314
        FastSerialHandler(_num,                                         \
315
                          USART##_num##_RX_vect,                        \
316
                          USART##_num##_UDRE_vect,                      \
317
                          UDR##_num,                                    \
318
                          UCSR##_num##B,                                \
319
                          _BV(UDRIE##_num))
320
 
321
///
322
/// Compatibility macros for previous FastSerial versions.
323
///
324
/// Note that these are not conditionally defined, as the errors
325
/// generated when using these macros for a board that does not support
326
/// the port are better than the errors generated for a macro that's not
327
/// defined at all.
328
///
329
#define FastSerialPort0(_portName)     FastSerialPort(_portName, 0)
330
#define FastSerialPort1(_portName)     FastSerialPort(_portName, 1)
331
#define FastSerialPort2(_portName)     FastSerialPort(_portName, 2)
332
#define FastSerialPort3(_portName)     FastSerialPort(_portName, 3)
333
 
334
#endif // FastSerial_h