diff --git a/Libraries/SerialPort/SerialPort.cpp b/Libraries/SerialPort/SerialPort.cpp index 44b62db..909f641 100644 --- a/Libraries/SerialPort/SerialPort.cpp +++ b/Libraries/SerialPort/SerialPort.cpp @@ -17,9 +17,16 @@ * along with the Arduino SerialPort Library. If not, see * . */ +/** + * @file + * @brief Serial Port class + */ #include //------------------------------------------------------------------------------ -/** \return the number of bytes in the ring buffer */ +/** @return The number of bytes in the ring buffer. + * + * @note This function must not be called with interrupts disabled. + */ int SerialRingBuffer::available() { uint8_t s = SREG; cli(); @@ -28,7 +35,10 @@ int SerialRingBuffer::available() { return n < 0 ? size_ + n : n; } //------------------------------------------------------------------------------ -/** Discard all data in the ring buffer. */ +/** Discard all data in the ring buffer. + * + * @note This function must not be called with interrupts disabled. + */ void SerialRingBuffer::flush() { uint8_t s = SREG; cli(); @@ -36,9 +46,10 @@ void SerialRingBuffer::flush() { 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 +/** Get the next byte from the ring buffer. + * + * @param[in] b location for the returned byte + * @return @c true if a byte was returned or @c false if the ring buffer is empty */ bool SerialRingBuffer::get(uint8_t* b) { buf_size_t t = tail_; @@ -50,12 +61,13 @@ bool SerialRingBuffer::get(uint8_t* b) { //------------------------------------------------------------------------------ /** * Get the maximum number of contiguous bytes from the ring buffer - * with one call to memcpy. Do not use this function with interrupts - * disabled. + * with one call to memcpy. * - * \param[in] b pointer to data - * \param[in] n number of bytes to transfer from the ring buffer - * \return number of bytes transferred + * @note This function must not be called with interrupts disabled. + * + * @param[in] b Pointer to the 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; @@ -77,9 +89,9 @@ SerialRingBuffer::buf_size_t SerialRingBuffer::get(uint8_t* b, buf_size_t n) { return nr; } //------------------------------------------------------------------------------ -/** initialize the ring buffer - * \param[in] b buffer for data - * \param[in] s size of the buffer +/** Initialize the ring buffer. + * @param[in] b Buffer for the data. + * @param[in] s Size of the buffer. */ void SerialRingBuffer::init(uint8_t* b, buf_size_t s) { buf_ = b; @@ -87,20 +99,22 @@ void SerialRingBuffer::init(uint8_t* b, buf_size_t 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 +/** Peek at the next byte in the ring buffer. + * @return The next byte that would be 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 +/** Put a byte into the ring buffer. + * + * @param[in] b the byte + * @return @c true if byte was transferred or + * @c 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 + // OK to store here even if ring is full. buf_[h++] = b; if (h >= size_) h = 0; if (h == tail_) return false; @@ -109,12 +123,14 @@ bool SerialRingBuffer::put(uint8_t b) { } //------------------------------------------------------------------------------ /** - * Put the maximum number of contiguous bytes into the ring buffer + * 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 + * @note This function must not be called with interrupts disabled. + * + * @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) { @@ -137,12 +153,14 @@ SerialRingBuffer::buf_size_t } //------------------------------------------------------------------------------ /** - * Put the maximum number of contiguous bytes into the ring buffer + * 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 + * @note This function must not be called with interrupts disabled. + * + * @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(); @@ -190,19 +208,25 @@ inline static void rx_isr(uint8_t n) { // 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); } +#elif defined(SIG_USART0_RECV) +ISR(SIG_USART0_RECV) { + rx_isr(0); +} +#elif defined(SIG_UART0_RECV) +ISR(SIG_UART0_RECV) { + rx_isr(0); +} +#elif defined(USART0_RX_vect) +ISR(USART0_RX_vect) { + rx_isr(0); +} +#elif defined(SIG_UART_RECV) +ISR(SIG_UART_RECV) { + rx_isr(0); +} +#endif // vector USART0 #ifdef USART1_RX_vect ISR(USART1_RX_vect) { rx_isr(1); @@ -237,17 +261,22 @@ inline static void tx_isr(uint8_t n) { } #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); } +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect) { + tx_isr(0); +} +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect) { + tx_isr(0); +} +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect) { + tx_isr(0); +} +#endif // USART0 TX + #ifdef USART1_UDRE_vect ISR(USART1_UDRE_vect) { tx_isr(1); diff --git a/Libraries/SerialPort/SerialPort.h b/Libraries/SerialPort/SerialPort.h index 3efeec2..4f028ad 100644 --- a/Libraries/SerialPort/SerialPort.h +++ b/Libraries/SerialPort/SerialPort.h @@ -1,5 +1,5 @@ /* Arduino SerialPort Library - * Copyright (C) 2011 by William Greiman + * Copyright (C) 2012 by William Greiman * * This file is part of the Arduino SerialPort Library * @@ -17,18 +17,19 @@ * along with the Arduino SerialPort Library. If not, see * . */ - /** - * \file - * \brief SerialPort class +/** + * @file + * @brief Serial Port class */ #ifndef SerialPort_h #define SerialPort_h //------------------------------------------------------------------------------ /** SerialPort version YYYYMMDD */ -#define SERIAL_PORT_VERSION 20120106 +#define SERIAL_PORT_VERSION 20140216 //------------------------------------------------------------------------------ /** * Set ALLOW_LARGE_BUFFERS to zero to limit buffer sizes to 254 bytes. + * * ALLOW_LARGE_BUFFERS controls whether uint16_t or uint8_t will be * used for buffer indices. */ @@ -36,13 +37,15 @@ //------------------------------------------------------------------------------ /** * Set USE_WRITE_OVERRIDES to zero to use the Arduino Print version - * of write(const char*) and write(const uint8_t*, size_t). This will - * save some flash but is much slower. + * of write(const char*) and write(const uint8_t*, size_t). + * + * This will save some flash but is much slower. */ #define USE_WRITE_OVERRIDES 1 //------------------------------------------------------------------------------ /** * Set BUFFERED_RX zero to save flash and RAM if no RX buffering is used. + * * RxBufSize must be zero in all SerialPort constructors if * BUFFERED_RX is zero. */ @@ -50,6 +53,7 @@ //------------------------------------------------------------------------------ /** * Set BUFFERED_TX zero to save flash and RAM if no TX buffering is used. + * * TxBufSize must be zero in all SerialPort constructors if * BUFFERED_TX is zero. */ @@ -72,14 +76,7 @@ //------------------------------------------------------------------------------ #include #include -#if ARDUINO < 100 -#include -class __FlashStringHelper; -#define F(string_literal)\ - (reinterpret_cast<__FlashStringHelper *>(PSTR(string_literal))) -#else // ARDUINO < 100 #include -#endif // ARDUINO < 100 //------------------------------------------------------------------------------ #if defined(UCSR3A) static const uint8_t SERIAL_PORT_COUNT = 4; @@ -90,11 +87,11 @@ static const uint8_t SERIAL_PORT_COUNT = 2; #elif defined(UCSR0A) || defined(UCSRA) static const uint8_t SERIAL_PORT_COUNT = 1; #else -#error no serial ports +#error no serial ports. #endif //------------------------------------------------------------------------------ #ifdef UCSR0A -// bits in UCSRA +// Bits in UCSRA. static const uint8_t M_RXC = 1 << RXC0; static const uint8_t M_TXC = 1 << TXC0; static const uint8_t M_UDRE = 1 << UDRE0; @@ -102,20 +99,20 @@ static const uint8_t M_FE = 1 << FE0; static const uint8_t M_DOR = 1 << DOR0; static const uint8_t M_UPE = 1 << UPE0; static const uint8_t M_U2X = 1 << U2X0; -// bits in UCSRB +// Bits in UCSRB. static const uint8_t M_RXCIE = 1 << RXCIE0; static const uint8_t M_TXCIE = 1 << TXCIE0; static const uint8_t M_UDRIE = 1 << UDRIE0; static const uint8_t M_RXEN = 1 << RXEN0; static const uint8_t M_TXEN = 1 << TXEN0; -// bits in UCSRC +// Bits in UCSRC. static const uint8_t M_UPM0 = 1 << UPM00; static const uint8_t M_UPM1 = 1 << UPM01; static const uint8_t M_USBS = 1 << USBS0; static const uint8_t M_UCSZ0 = 1 << UCSZ00; static const uint8_t M_UCSZ1 = 1 << UCSZ01; #elif defined(UCSRA) // UCSR0A -// bits in UCSRA +// Bits in UCSRA. static const uint8_t M_RXC = 1 << RXC; static const uint8_t M_TXC = 1 << TXC; static const uint8_t M_UDRE = 1 << UDRE; @@ -123,67 +120,91 @@ static const uint8_t M_FE = 1 << FE; static const uint8_t M_DOR = 1 << DOR; static const uint8_t M_UPE = 1 << PE; static const uint8_t M_U2X = 1 << U2X; -// bits in UCSRB +// Bits in UCSRB. static const uint8_t M_RXCIE = 1 << RXCIE; static const uint8_t M_TXCIE = 1 << TXCIE; static const uint8_t M_UDRIE = 1 << UDRIE; static const uint8_t M_RXEN = 1 << RXEN; static const uint8_t M_TXEN = 1 << TXEN; -// bits in UCSRC +// Bits in UCSRC. static const uint8_t M_UPM0 = 1 << UPM0; static const uint8_t M_UPM1 = 1 << UPM1; static const uint8_t M_USBS = 1 << USBS; static const uint8_t M_UCSZ0 = 1 << UCSZ0; static const uint8_t M_UCSZ1 = 1 << UCSZ1; +#elif defined(UCSR1A) // UCSR0A +// Bits in UCSRA. +static const uint8_t M_RXC = 1 << RXC1; +static const uint8_t M_TXC = 1 << TXC1; +static const uint8_t M_UDRE = 1 << UDRE1; +static const uint8_t M_FE = 1 << FE1; +static const uint8_t M_DOR = 1 << DOR1; +static const uint8_t M_UPE = 1 << UPE1; +static const uint8_t M_U2X = 1 << U2X1; +// Bits in UCSRB. +static const uint8_t M_RXCIE = 1 << RXCIE1; +static const uint8_t M_TXCIE = 1 << TXCIE1; +static const uint8_t M_UDRIE = 1 << UDRIE1; +static const uint8_t M_RXEN = 1 << RXEN1; +static const uint8_t M_TXEN = 1 << TXEN1; +// Bits in UCSRC. +static const uint8_t M_UPM0 = 1 << UPM10; +static const uint8_t M_UPM1 = 1 << UPM11; +static const uint8_t M_USBS = 1 << USBS1; +static const uint8_t M_UCSZ0 = 1 << UCSZ10; +static const uint8_t M_UCSZ1 = 1 << UCSZ11; #else // UCSR0A #error no serial ports #endif // UCSR0A //------------------------------------------------------------------------------ -/** use one stop bit */ +/** Use one stop bit. */ static const uint8_t SP_1_STOP_BIT = 0; -/** use two stop bits */ +/** Use two stop bits. */ static const uint8_t SP_2_STOP_BIT = M_USBS; -/** disable parity bit */ +/** No parity bit. */ static const uint8_t SP_NO_PARITY = 0; -/** use even parity */ +/** Use even parity. */ static const uint8_t SP_EVEN_PARITY = M_UPM1; -/** use odd parity */ +/** Use odd parity. */ static const uint8_t SP_ODD_PARITY = M_UPM0 | M_UPM1; -/** use 5-bit character size */ +/** Use 5-bit character size. */ static const uint8_t SP_5_BIT_CHAR = 0; -/** use 6-bit character size */ +/** Use 6-bit character size. */ static const uint8_t SP_6_BIT_CHAR = M_UCSZ0; -/** use 7-bit character size */ +/** Use 7-bit character size. */ static const uint8_t SP_7_BIT_CHAR = M_UCSZ1; -/** use 8-bit character size */ +/** Use 8-bit character size. */ static const uint8_t SP_8_BIT_CHAR = M_UCSZ0 | M_UCSZ1; -/** mask for all options bits */ +/** Mask for all options bits. */ static const uint8_t SP_OPT_MASK = M_USBS | M_UPM0 | M_UPM1 |M_UCSZ0 | M_UCSZ1; -/** USART frame error bit */ +/** USART framing error bit. */ static const uint8_t SP_FRAMING_ERROR = M_FE; -/** USART RX data overrun error bit */ +/** USART RX data overrun error bit. */ static const uint8_t SP_RX_DATA_OVERRUN = M_DOR; -/** USART parity error bit */ +/** USART parity error bit. */ static const uint8_t SP_PARITY_ERROR = M_UPE; -/** mask for all error bits in UCSRA */ +/** Mask for all error bits in UCSRA. */ static const uint8_t SP_UCSRA_ERROR_MASK = M_FE | M_DOR | M_UPE; -/** RX ring buffer full overrun */ +/** RX ring buffer full overrun. */ static const uint8_t SP_RX_BUF_OVERRUN = 1; +#if 1 & ((1 << FE0) | (1 << DOR0) |(1 << UPE0)) +#error Invalid SP_RX_BUF_OVERRUN bit +#endif // SP_RX_BUF_OVERRUN //------------------------------------------------------------------------------ /** - * \class UsartRegister - * \brief addresses of USART registers + * @class UsartRegister + * @brief Addresses of USART registers. */ struct UsartRegister { - volatile uint8_t* ucsra; /**< USART Control and Status Register A */ - volatile uint8_t* ucsrb; /**< USART Control and Status Register B */ - volatile uint8_t* ucsrc; /**< USART Control and Status Register C */ - volatile uint8_t* ubrrl; /**< USART Baud Rate Register Low */ - volatile uint8_t* ubrrh; /**< USART Baud Rate Register High */ - volatile uint8_t* udr; /**< USART I/O Data Register */ + volatile uint8_t* ucsra; /**< USART Control and Status Register A. */ + volatile uint8_t* ucsrb; /**< USART Control and Status Register B. */ + volatile uint8_t* ucsrc; /**< USART Control and Status Register C. */ + volatile uint8_t* ubrrl; /**< USART Baud Rate Register Low. */ + volatile uint8_t* ubrrh; /**< USART Baud Rate Register High. */ + volatile uint8_t* udr; /**< USART I/O Data Register. */ }; //------------------------------------------------------------------------------ /** @@ -219,8 +240,8 @@ static const UsartRegister usart[] = { }; //------------------------------------------------------------------------------ /** - * \class SerialRingBuffer - * \brief ring buffer for RX and TX data + * @class SerialRingBuffer + * @brief Ring buffer for RX and TX data. */ class SerialRingBuffer { public: @@ -231,7 +252,7 @@ class SerialRingBuffer { typedef uint8_t buf_size_t; #endif // ALLOW_LARGE_BUFFERS int available(); - /** \return true if the ring buffer is empty else false */ + /** @return @c true if the ring buffer is empty else @c false. */ bool empty() {return head_ == tail_;} void flush(); bool get(uint8_t* b); @@ -248,49 +269,52 @@ class SerialRingBuffer { buf_size_t size_; /**< Size of the buffer. Capacity is size -1. */ }; //------------------------------------------------------------------------------ -/** RX ring buffers */ +/** RX ring buffers. */ extern SerialRingBuffer rxRingBuf[]; -/** TX ring buffers */ +/** TX ring buffers. */ extern SerialRingBuffer txRingBuf[]; -/** RX error bits */ +/** RX error bits. */ extern uint8_t rxErrorBits[]; //------------------------------------------------------------------------------ -/** Cause error message for bad port number - * \return Never returns since it is never called +/** Cause error message for bad port number. + * @return Never returns since it is never called. */ uint8_t badPortNumber(void) __attribute__((error("Bad port number"))); -/** Cause error message for bad port number - * \return Never returns since it is never called +/** Cause error message for bad port number. + * @return Never returns since it is never called. */ uint8_t badRxBufSize(void) __attribute__((error("RX buffer size too large"))); -/** Cause error message for bad port number - * \return Never returns since it is never called +/** Cause error message for bad port number. + * @return Never returns since it is never called. */ uint8_t badTxBufSize(void) __attribute__((error("TX buffer size too large"))); //------------------------------------------------------------------------------ /** - * \class SerialPort - * \brief class for avr hardware USART ports + * @class SerialPort + * @brief Class for avr hardware USART ports. */ template class SerialPort : public Stream { public: //---------------------------------------------------------------------------- + /** Constructor */ SerialPort() { - if (PortNumber >= SERIAL_PORT_COUNT) badPortNumber(); + if (PortNumber >= SERIAL_PORT_COUNT || !usart[PortNumber].ucsra) { + badPortNumber(); + } if (sizeof(SerialRingBuffer::buf_size_t) == 1) { - if (RxBufSize >254) badRxBufSize(); - if (TxBufSize >254) badTxBufSize(); + if (RxBufSize > 254) badRxBufSize(); + if (TxBufSize > 254) badTxBufSize(); } if (RxBufSize) rxRingBuf[PortNumber].init(rxBuffer_, sizeof(rxBuffer_)); if (TxBufSize) txRingBuf[PortNumber].init(txBuffer_, sizeof(txBuffer_)); } //---------------------------------------------------------------------------- /** - * \return The number of bytes (characters) available for reading from + * @return The number of bytes (characters) available for reading from * the serial port. */ int available(void) { @@ -304,31 +328,23 @@ class SerialPort : public Stream { /** * Sets the data rate in bits per second (baud) for serial data transmission. * - * \param[in] baud rate in bits per second (baud) - * \param[in] options constructed by a bitwise-inclusive + * @param[in] baud Rate in bits per second (baud). + * @param[in] options constructed by a bitwise-inclusive * OR of values from the following list. Choose one value for stop bit, * parity, and character size. * + * - SP_1_STOP_BIT - Use one stop bit (default if stop bit not specified). + * - SP_2_STOP_BIT - Use two stop bits. + * - SP_NO_PARITY - No parity bit (default if parity not specified). + * - SP_EVEN_PARITY - Add even parity bit. + * - SP_ODD_PARITY - Add odd parity bit. + * - SP_5_BIT_CHAR - Use 5-bit characters (default if size not specified). + * - SP_6_BIT_CHAR - Use 6-bit characters. + * - SP_7_BIT_CHAR - Use 7-bit characters. + * - SP_8_BIT_CHAR - Use 8-bit characters. + * . * The default is SP_8_BIT_CHAR which results in one stop bit, no parity, * and 8-bit characters. - * - * SP_1_STOP_BIT - use one stop bit (default if stop bit not specified) - * - * SP_2_STOP_BIT - use two stop bits - * - * SP_NO_PARITY - no parity bit (default if parity not specified) - * - * SP_EVEN_PARITY - add even parity bit - * - * SP_ODD_PARITY - add odd parity bit - * - * SP_5_BIT_CHAR - use 5-bit characters (default if size not specified) - * - * SP_6_BIT_CHAR - use 6-bit characters - * - * SP_7_BIT_CHAR - use 7-bit characters - * - * SP_8_BIT_CHAR - use 8-bit characters */ void begin(uint32_t baud, uint8_t options = SP_8_BIT_CHAR) { uint16_t baud_setting; @@ -339,16 +355,22 @@ class SerialPort : public Stream { // set option bits *usart[PortNumber].ucsrc = options & SP_OPT_MASK; - if (F_CPU == 16000000UL && baud == 57600) { - // hardcoded exception for compatibility with the bootloader shipped - // with the Duemilanove and previous boards and the firmware on the 8U2 - // on the Uno and Mega 2560. + baud_setting = F_CPU/4/baud; + + if (baud_setting > 8192 || (F_CPU == 16000000UL && baud == 57600)) { + // Hardcoded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards and the firmware on the + // 8U2/16U2 on the Uno and Mega 2560. + // Prevent overflow of 12-bit UBRR at 300 baud. *usart[PortNumber].ucsra = 0; - baud_setting = (F_CPU / 8 / baud - 1) / 2; + baud_setting /= 2; } else { + // Use U2X for better high baud rates. *usart[PortNumber].ucsra = M_U2X; - baud_setting = (F_CPU / 4 / baud - 1) / 2; } + // Rounded value for datasheet expression. + baud_setting = (baud_setting - 1)/2; + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) *usart[PortNumber].ubrrh = baud_setting >> 8; *usart[PortNumber].ubrrl = baud_setting; @@ -362,9 +384,15 @@ class SerialPort : public Stream { } //---------------------------------------------------------------------------- #if ENABLE_RX_ERROR_CHECKING - /** clear RX error bits */ + /** Clear RX error bits. */ void clearRxError() {rxErrorBits[PortNumber] = 0;} - /** \return RX error bits */ + /** @return RX error bits. Possible error bits are: + * - @ref SP_RX_BUF_OVERRUN + * - @ref SP_RX_DATA_OVERRUN + * - @ref SP_FRAMING_ERROR + * - @ref SP_PARITY_ERROR + * . + */ uint8_t getRxError() {return rxErrorBits[PortNumber];} #endif // ENABLE_RX_ERROR_CHECKING //---------------------------------------------------------------------------- @@ -386,13 +414,8 @@ class SerialPort : public Stream { //---------------------------------------------------------------------------- /** * For Arduino 1.0 and greater call flushTx(). - * For Arduino 0023 and before call flushRx(). */ - #if ARDUINO < 100 - void flush() {flushRx();} - #else // ARDUINO < 100 void flush() {flushTx();} - #endif // ARDUINO < 100 //---------------------------------------------------------------------------- /** * Discard any buffered incoming serial data. @@ -416,8 +439,8 @@ class SerialPort : public Stream { } //---------------------------------------------------------------------------- /** - * \return the first byte of incoming serial data available or - * -1 if no data is available. Peek() always return -1 for unbuffered RX. + * @return The first byte of incoming serial data available or + * -1 if no data is available. -1 is always returned for unbuffered RX. */ int peek(void) { return RxBufSize ? rxRingBuf[PortNumber].peek() : -1; @@ -426,8 +449,8 @@ class SerialPort : public Stream { /** * Read incoming serial data. * - * \return the first byte of incoming serial data available - * or -1 if no data is available + * @return The first byte of incoming serial data available + * or -1 if no data is available. */ __attribute__((noinline)) int read() { @@ -447,9 +470,9 @@ class SerialPort : public Stream { * Read incoming serial data. Stop when RX buffer is empty or n * bytes have been read. * - * \param[in] b location to receive the data - * \param[in] n maximum number of bytes to read - * \return number of bytes read + * @param[in] b The location to receive the data. + * @param[in] n Maximum number of bytes to read. + * @return The number of bytes read. */ __attribute__((noinline)) size_t read(uint8_t* b, size_t n) { @@ -461,7 +484,6 @@ class SerialPort : public Stream { if (sizeof(SerialRingBuffer::buf_size_t) == 1 && nr > 255) nr = 255; p += rxRingBuf[PortNumber].get(p, nr); } - return p - b; } else { while (p < limit) { int rb = read(); @@ -475,77 +497,55 @@ class SerialPort : public Stream { /** * Write binary data to the serial port. * - * \param[in] b byte to be written. - * \return number of bytes written to the serial port + * @param[in] b The byte to be written. + * @return The number of bytes written to the serial port. */ __attribute__((noinline)) - #if ARDUINO < 100 - void write(uint8_t b) { - #else // ARDUINO < 100 size_t write(uint8_t b) { - #endif // ARDUINO < 100 if (!TxBufSize) { while (!(*usart[PortNumber].ucsra & M_UDRE)) {} *usart[PortNumber].udr = b; } else { - // wait for TX ISR if buffer is full + // Wait for TX ISR if buffer is full. while (!txRingBuf[PortNumber].put(b)) {} - // enable interrupts + + // Enable interrupts. *usart[PortNumber].ucsrb |= M_UDRIE; } - #if ARDUINO > 99 return 1; - #endif // ARDUINO > 99 } //---------------------------------------------------------------------------- - /** write CR LF - * \return 2 + /** Write CR/LF. + * @return 2 */ __attribute__((noinline)) - #if ARDUINO < 100 - void writeln() { - write('\r'); - write('\n'); - } - #else // ARDUINO < 100 size_t writeln() { write('\r'); write('\n'); return 2; } - #endif // ARDUINO >= 100 //---------------------------------------------------------------------------- /** - * Write a string to the serial port followed by CF LF + * Write a string to the serial port followed by CR/LF. * - * \param[in] s string to be written. - * \return number of bytes written to the serial port + * @param[in] s The string to be written. + * @return The number of bytes written to the serial port. */ __attribute__((noinline)) - #if ARDUINO < 100 - void writeln(const char* s) { - write(s); - writeln(); - } - #else // ARDUINO < 100 size_t writeln(const char* s) { return write(s) + writeln(); } - #endif // ARDUINO >= 100 + //---------------------------------------------------------------------------- /** * Write binary data from flash memory to the serial port. * - * \param[in] b bytes to be written - * \param[in] n number of bytes to write - * \return number of bytes written to the serial port + * @param[in] b Location of the bytes to be written. + * @param[in] n The number of bytes to write. + * @return The number of bytes written to the serial port. */ __attribute__((noinline)) - #if ARDUINO < 100 - void write_P(PGM_P b, size_t n) { - #else // ARDUINO < 100 size_t write_P(PGM_P b, size_t n) { - #endif // ARDUINO < 100 if (!TxBufSize) { for (size_t i = 0; i < n; i++) write(pgm_read_byte(b + i)); } else { @@ -554,70 +554,50 @@ class SerialPort : public Stream { size_t nw = w; if (sizeof(SerialRingBuffer::buf_size_t) == 1 && nw > 255) nw = 255; size_t m = txRingBuf[PortNumber].put_P(b, nw); + // enable interrupts *usart[PortNumber].ucsrb |= M_UDRIE; w -= m; b += m; } } - #if ARDUINO >= 100 return n; - #endif // ARDUINO >= 100 } //---------------------------------------------------------------------------- /** * Write a flash string to the serial port. * - * \param[in] s string to be written. - * \return number of bytes written to the serial port + * @param[in] s The string to be written. + * @return The number of bytes written to the serial port. */ __attribute__((noinline)) - #if ARDUINO < 100 - void write(const __FlashStringHelper* s) { - const prog_char* p = (const prog_char*)s; - size_t n = strlen_P(p); - write_P(p, n); - } - #else // ARDUINO < 100 size_t write(const __FlashStringHelper* s) { - const prog_char* p = (const prog_char*)s; + const char PROGMEM* p = (const char PROGMEM*)s; size_t n = strlen_P(p); return write_P(p, n); } - #endif // ARDUINO >= 100 //---------------------------------------------------------------------------- /** - * Write a flash string to the serial port followed by CF LF + * Write a flash string to the serial port followed by CR/LF. * - * \param[in] s string to be written. - * \return number of bytes written to the serial port + * @param[in] s The string to be written. + * @return The number of bytes written to the serial port. */ __attribute__((noinline)) - #if ARDUINO < 100 - void writeln(const __FlashStringHelper* s) { - write(s); - writeln(); - } - #else // ARDUINO < 100 size_t writeln(const __FlashStringHelper* s) { return write(s) + writeln(); } - #endif // ARDUINO >= 100 #if USE_WRITE_OVERRIDES //---------------------------------------------------------------------------- /** * Write binary data to the serial port. * - * \param[in] b bytes to be written - * \param[in] n number of bytes to write - * \return number of bytes written to the serial port + * @param[in] b Location of the bytes to be written. + * @param[in] n The number of bytes to write. + * @return The number of bytes written to the serial port. */ __attribute__((noinline)) - #if ARDUINO < 100 - void write(const uint8_t* b, size_t n) { - #else // ARDUINO < 100 size_t write(const uint8_t* b, size_t n) { - #endif // ARDUINO < 100 if (!TxBufSize) { for (size_t i = 0; i < n; i++) write(b[i]); } else { @@ -626,35 +606,27 @@ class SerialPort : public Stream { size_t nw = w; if (sizeof(SerialRingBuffer::buf_size_t) == 1 && nw > 255) nw = 255; size_t m = txRingBuf[PortNumber].put(b, nw); - // enable interrupts + + // Enable interrupts. *usart[PortNumber].ucsrb |= M_UDRIE; w -= m; b += m; } } - #if ARDUINO >= 100 return n; - #endif // ARDUINO >= 100 } //---------------------------------------------------------------------------- /** * Write a string to the serial port. * - * \param[in] s string to be written. - * \return number of bytes written to the serial port + * @param[in] s The string to be written. + * @return The number of bytes written to the serial port */ __attribute__((noinline)) - #if ARDUINO < 100 - void write(const char* s) { - size_t n = strlen(s); - write(reinterpret_cast(s), n); - } - #else // ARDUINO < 100 size_t write(const char* s) { size_t n = strlen(s); return write(reinterpret_cast(s), n); } - #endif // ARDUINO >= 100 #else // USE_WRITE_OVERRIDES using Print::write; // use write(str) and write(buf, size) from Print #endif // USE_WRITE_OVERRIDES @@ -662,7 +634,7 @@ class SerialPort : public Stream { private: // RX buffer with a capacity of RxBufSize. uint8_t rxBuffer_[RxBufSize + 1]; - // TX buffer with a capacity of TxBufSize + // TX buffer with a capacity of TxBufSize. uint8_t txBuffer_[TxBufSize + 1]; }; //------------------------------------------------------------------------------ diff --git a/Libraries/SerialPort/examples/ArduinoSize/ArduinoSize.ino b/Libraries/SerialPort/examples/ArduinoSize/ArduinoSize.ino new file mode 100644 index 0000000..f8894ad --- /dev/null +++ b/Libraries/SerialPort/examples/ArduinoSize/ArduinoSize.ino @@ -0,0 +1,10 @@ +// Print free RAM for Arduino HardwareSerial +// +#include "FreeRam.h" + +void setup() { + Serial.begin(9600); + Serial.println(FreeRam()); +} +void loop() { +} diff --git a/Libraries/SerialPort/examples/ArduinoSize/FreeRam.h b/Libraries/SerialPort/examples/ArduinoSize/FreeRam.h index b03537c..bbd9dd3 100644 --- a/Libraries/SerialPort/examples/ArduinoSize/FreeRam.h +++ b/Libraries/SerialPort/examples/ArduinoSize/FreeRam.h @@ -1,15 +1,10 @@ +#include static inline int FreeRam() { - extern int __bss_end; - extern int* __brkval; - int free_memory; - if (reinterpret_cast(__brkval) == 0) { - // if no heap use from end of bss section - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(&__bss_end); - } else { - // use from top of stack to heap - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(__brkval); - } - return free_memory; + extern char *__brkval; + char top; +#if defined(CORE_TEENSY) + return &top - __brkval; +#else // malloc type + return __brkval ? &top - __brkval : &top - __malloc_heap_start; +#endif // malloc type } diff --git a/Libraries/SerialPort/examples/ArduinoTest/ArduinoTest.ino b/Libraries/SerialPort/examples/ArduinoTest/ArduinoTest.ino new file mode 100644 index 0000000..7b23808 --- /dev/null +++ b/Libraries/SerialPort/examples/ArduinoTest/ArduinoTest.ino @@ -0,0 +1,20 @@ + +void setup() { + Serial.begin(9600); + uint32_t t = micros(); + Serial.write("This string is used to measure the time to buffer data.\r\n"); + t = micros() - t; + Serial.write("Time: "); + Serial.print(t); + Serial.write(" us\r\n"); +} +void loop() { + Serial.write("\r\nenter a string\r\n"); + while (!Serial.available()) {} + do { + Serial.write(Serial.read()); + uint32_t m = millis(); + while (!Serial.available() && (millis() - m) < 3) {} + } while(Serial.available()); + Serial.write("\r\n"); +} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/BufferedSize/BufferedSize.ino b/Libraries/SerialPort/examples/BufferedSize/BufferedSize.ino new file mode 100644 index 0000000..86089a0 --- /dev/null +++ b/Libraries/SerialPort/examples/BufferedSize/BufferedSize.ino @@ -0,0 +1,15 @@ +// Print free RAM for Arduino 1.0 style buffering. +// +#include +#include "FreeRam.h" + +SerialPort<0, 63, 63> NewSerial; + +// for Arduino 0022 style buffering use this +//SerialPort<0, 127, 0> NewSerial; + +void setup() { + NewSerial.begin(9600); + NewSerial.println(FreeRam()); +} +void loop() {} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/BufferedSize/FreeRam.h b/Libraries/SerialPort/examples/BufferedSize/FreeRam.h index b03537c..bbd9dd3 100644 --- a/Libraries/SerialPort/examples/BufferedSize/FreeRam.h +++ b/Libraries/SerialPort/examples/BufferedSize/FreeRam.h @@ -1,15 +1,10 @@ +#include static inline int FreeRam() { - extern int __bss_end; - extern int* __brkval; - int free_memory; - if (reinterpret_cast(__brkval) == 0) { - // if no heap use from end of bss section - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(&__bss_end); - } else { - // use from top of stack to heap - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(__brkval); - } - return free_memory; + extern char *__brkval; + char top; +#if defined(CORE_TEENSY) + return &top - __brkval; +#else // malloc type + return __brkval ? &top - __brkval : &top - __malloc_heap_start; +#endif // malloc type } diff --git a/Libraries/SerialPort/examples/BufferedTest/BufferedTest.ino b/Libraries/SerialPort/examples/BufferedTest/BufferedTest.ino new file mode 100644 index 0000000..489fdfd --- /dev/null +++ b/Libraries/SerialPort/examples/BufferedTest/BufferedTest.ino @@ -0,0 +1,25 @@ +// Check time to buffer data and function of available(). +#include + +// port zero, 63 character RX and TX buffers +SerialPort<0, 63, 63> NewSerial; + +void setup() { + NewSerial.begin(9600); + uint32_t t = micros(); + NewSerial.write("This string is used to measure the time to buffer data.\r\n"); + t = micros() - t; + NewSerial.write("Time: "); + NewSerial.print(t); + NewSerial.write(" us\r\n"); +} +void loop() { + NewSerial.write("\r\nenter a string\r\n"); + while (!NewSerial.available()) {} + do { + NewSerial.write(NewSerial.read()); + uint32_t m = millis(); + while (!NewSerial.available() && (millis() - m) < 3) {} + } while(NewSerial.available()); + NewSerial.write("\r\n"); +} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/HelloWorld/HelloWorld.ino b/Libraries/SerialPort/examples/HelloWorld/HelloWorld.ino new file mode 100644 index 0000000..086d820 --- /dev/null +++ b/Libraries/SerialPort/examples/HelloWorld/HelloWorld.ino @@ -0,0 +1,11 @@ +// Simple usage with buffering like Arduino 1.0. +#include + +// use NewSerial for port 0 +USE_NEW_SERIAL; + +void setup() { + NewSerial.begin(9600); + NewSerial.println("Hello World!"); +} +void loop() {} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/MegaTest/MegaTest.ino b/Libraries/SerialPort/examples/MegaTest/MegaTest.ino new file mode 100644 index 0000000..7dca6fc --- /dev/null +++ b/Libraries/SerialPort/examples/MegaTest/MegaTest.ino @@ -0,0 +1,48 @@ +// Test all ports on the Mega. +// +// A string read on port zero will be sent to port one, +// it will then be read from port one and sent to port +// two, next it will be read from port two and sent to +// port three, and finally it will be read from port +// three and sent to port zero. +// +// Place a loopback jumper connecting +// RX1 to TX1, RX2 to TX2, RX3 to TX3 on ports 1, 2, and 3. +// Do not place a jumper on port zero. +// +#include +// port 0 unbuffered +SerialPort<0, 0, 0> port0; + +// port 1 buffered RX +SerialPort<1, 32, 0> port1; + +// port 2 buffered RX and TX +SerialPort<2, 32, 32> port2; + +// port 3 buffered RX and TX +SerialPort<3, 32, 32> port3; + +void transfer(Stream* in, Stream* out) { + while(!in->available()) {} + do { + out->write(in->read()); + uint32_t m = millis(); + while (!in->available() && (millis() -m) < 3) {} + } while (in->available()); +} + +void setup() { + port0.begin(9600); + port1.begin(9600); + port2.begin(9600); + port3.begin(9600); +} +void loop() { + port0.write("type a string\r\n"); + transfer(&port0, &port1); + transfer(&port1, &port2); + transfer(&port2, &port3); + transfer(&port3, &port0); + port0.write("\r\n\r\n"); +} diff --git a/Libraries/SerialPort/examples/MegaTestArduino/MegaTestArduino.ino b/Libraries/SerialPort/examples/MegaTestArduino/MegaTestArduino.ino new file mode 100644 index 0000000..32538ab --- /dev/null +++ b/Libraries/SerialPort/examples/MegaTestArduino/MegaTestArduino.ino @@ -0,0 +1,35 @@ +// Test all ports on the Mega. +// +// +// A string read on port zero will be sent to port one, +// it will then be read from port one and sent to port +// two, next it will be read from port two and sent to +// port three, and finally it will be read from port +// three and sent to port zero. +// +// Place a loopback jumper connecting +// RX1 to TX1, RX2 to TX2, RX3 to TX3 on ports 1, 2, and 3. +// Do not place a jumper on port zero. +// +void transfer(Stream* in, Stream* out) { + while(!in->available()) {} + do { + out->write(in->read()); + uint32_t m = millis(); + while (!in->available() && (millis() - m) < 3) {} + } while (in->available()); +} +void setup() { + Serial.begin(9600); + Serial1.begin(9600); + Serial2.begin(9600); + Serial3.begin(9600); +} +void loop() { + Serial.write("type a string\r\n"); + transfer(&Serial, &Serial1); + transfer(&Serial1, &Serial2); + transfer(&Serial2, &Serial3); + transfer(&Serial3, &Serial); + Serial.write("\r\n\r\n"); +} diff --git a/Libraries/SerialPort/examples/ReadWriteTest/ReadWriteTest.ino b/Libraries/SerialPort/examples/ReadWriteTest/ReadWriteTest.ino new file mode 100644 index 0000000..c1df3c8 --- /dev/null +++ b/Libraries/SerialPort/examples/ReadWriteTest/ReadWriteTest.ino @@ -0,0 +1,32 @@ +// Test that ring buffer overrun can be detected. +#include +// port 0, 16 byte RX and TX buffers +SerialPort<0, 16, 16> port0; + +void setup() { + port0.begin(9600); + port0.write("SerialPort version: "); + port0.println(SERIAL_PORT_VERSION); +} +void loop() { + uint8_t buffer[10]; + port0.writeln("Enter a string. Overrun error for more than 16 bytes."); + while (!port0.available()) {} + // delay so an ring buffer overrun will occur for long strings + delay(50); + uint32_t m = millis(); + do { + size_t n = port0.read(buffer, sizeof (buffer)); + if (n) { + m = millis(); + port0.write(buffer, n); + } + } while ((millis() - m) < 4); + port0.writeln(); + uint8_t e = port0.getRxError(); + if (e) { + port0.write("Error: "); + port0.println(e, HEX); + port0.clearRxError(); + } +} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/UnbufferedSize/FreeRam.h b/Libraries/SerialPort/examples/UnbufferedSize/FreeRam.h index b03537c..bbd9dd3 100644 --- a/Libraries/SerialPort/examples/UnbufferedSize/FreeRam.h +++ b/Libraries/SerialPort/examples/UnbufferedSize/FreeRam.h @@ -1,15 +1,10 @@ +#include static inline int FreeRam() { - extern int __bss_end; - extern int* __brkval; - int free_memory; - if (reinterpret_cast(__brkval) == 0) { - // if no heap use from end of bss section - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(&__bss_end); - } else { - // use from top of stack to heap - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(__brkval); - } - return free_memory; + extern char *__brkval; + char top; +#if defined(CORE_TEENSY) + return &top - __brkval; +#else // malloc type + return __brkval ? &top - __brkval : &top - __malloc_heap_start; +#endif // malloc type } diff --git a/Libraries/SerialPort/examples/UnbufferedSize/UnbufferedSize.ino b/Libraries/SerialPort/examples/UnbufferedSize/UnbufferedSize.ino new file mode 100644 index 0000000..4b1f60a --- /dev/null +++ b/Libraries/SerialPort/examples/UnbufferedSize/UnbufferedSize.ino @@ -0,0 +1,17 @@ +// Print free RAM for unbuffered mode. +// +// You can reduce flash and RAM use more by setting +// BUFFERED_TX and BUFFERED_RX zero in SerialPort.h +// to always disable buffering. +// +#include +#include "FreeRam.h" + +// no buffers +SerialPort<0, 0, 0> NewSerial; + +void setup() { + NewSerial.begin(9600); + NewSerial.println(FreeRam()); +} +void loop() {} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/UnbufferedTest/UnbufferedTest.ino b/Libraries/SerialPort/examples/UnbufferedTest/UnbufferedTest.ino new file mode 100644 index 0000000..9043410 --- /dev/null +++ b/Libraries/SerialPort/examples/UnbufferedTest/UnbufferedTest.ino @@ -0,0 +1,24 @@ +#include + +// serial port zero with no RX or TX buffering +SerialPort<0, 0, 0> NewSerial; + +void setup() { + NewSerial.begin(9600); + uint32_t t = micros(); + NewSerial.write("This string is used to measure the time to buffer data.\r\n"); + t = micros() - t; + NewSerial.write("Time: "); + NewSerial.print(t); + NewSerial.write(" us\r\n"); +} +void loop() { + NewSerial.write("\r\nenter a string\r\n"); + while (!NewSerial.available()) {} + do { + NewSerial.write(NewSerial.read()); + uint32_t m = millis(); + while (!NewSerial.available() && (millis() - m) < 3) {} + } while(NewSerial.available()); + NewSerial.write("\r\n"); +} \ No newline at end of file diff --git a/Libraries/SerialPort/examples/WriteFlash/WriteFlash.ino b/Libraries/SerialPort/examples/WriteFlash/WriteFlash.ino new file mode 100644 index 0000000..09a05b1 --- /dev/null +++ b/Libraries/SerialPort/examples/WriteFlash/WriteFlash.ino @@ -0,0 +1,20 @@ +// Test write() time for a flash string. +#include + +SerialPort<0, 0, 32> port; + +void setup(void) { + port.begin(9600); + + for (int route = 0; route < 11; route++) { + uint32_t start = micros(); + port.writeln(F("Selecting passenger route x")); + uint32_t stop = micros(); + port.write(F("Message time: ")); + port.print(stop - start, DEC); + port.writeln(F(" us")); + delay(400); + } + port.println(F("Done!")); +} +void loop(void) {}