diff --git a/required_libraries/SerialPort/SerialPort.cpp b/required_libraries/SerialPort/SerialPort.cpp new file mode 100644 index 0000000..44b62db --- /dev/null +++ b/required_libraries/SerialPort/SerialPort.cpp @@ -0,0 +1,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 + * . + */ +#include +//------------------------------------------------------------------------------ +/** \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 diff --git a/required_libraries/SerialPort/SerialPort.h b/required_libraries/SerialPort/SerialPort.h new file mode 100644 index 0000000..3efeec2 --- /dev/null +++ b/required_libraries/SerialPort/SerialPort.h @@ -0,0 +1,669 @@ +/* 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 + * . + */ + /** + * \file + * \brief SerialPort class + */ +#ifndef SerialPort_h +#define SerialPort_h +//------------------------------------------------------------------------------ +/** SerialPort version YYYYMMDD */ +#define SERIAL_PORT_VERSION 20120106 +//------------------------------------------------------------------------------ +/** + * 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. + */ +#define ALLOW_LARGE_BUFFERS 1 +//------------------------------------------------------------------------------ +/** + * 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. + */ +#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. + */ +#define BUFFERED_RX 1 +//------------------------------------------------------------------------------ +/** + * 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. + */ +#define BUFFERED_TX 1 +//------------------------------------------------------------------------------ +/** + * Set ENABLE_RX_ERROR_CHECKING zero to disable RX error checking. + */ +#define ENABLE_RX_ERROR_CHECKING 1 +//------------------------------------------------------------------------------ +// Define symbols to allocate 64 byte ring buffers with capacity for 63 bytes. +/** Define NewSerial with buffering like Arduino 1.0. */ +#define USE_NEW_SERIAL SerialPort<0, 63, 63> NewSerial +/** Define NewSerial1 with buffering like Arduino 1.0. */ +#define USE_NEW_SERIAL1 SerialPort<1, 63, 63> NewSerial1 +/** Define NewSerial2 with buffering like Arduino 1.0. */ +#define USE_NEW_SERIAL2 SerialPort<2, 63, 63> NewSerial2 +/** Define NewSerial3 with buffering like Arduino 1.0. */ +#define USE_NEW_SERIAL3 SerialPort<3, 63, 63> NewSerial3 +//------------------------------------------------------------------------------ +#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; +#elif defined(UCSR2A) +static const uint8_t SERIAL_PORT_COUNT = 3; +#elif defined(UCSR1A) +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 +#endif +//------------------------------------------------------------------------------ +#ifdef UCSR0A +// 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; +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 +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 +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 +static const uint8_t M_RXC = 1 << RXC; +static const uint8_t M_TXC = 1 << TXC; +static const uint8_t M_UDRE = 1 << UDRE; +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 +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 +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; +#else // UCSR0A +#error no serial ports +#endif // UCSR0A +//------------------------------------------------------------------------------ +/** use one stop bit */ +static const uint8_t SP_1_STOP_BIT = 0; +/** use two stop bits */ +static const uint8_t SP_2_STOP_BIT = M_USBS; + +/** disable parity bit */ +static const uint8_t SP_NO_PARITY = 0; +/** use even parity */ +static const uint8_t SP_EVEN_PARITY = M_UPM1; +/** use odd parity */ +static const uint8_t SP_ODD_PARITY = M_UPM0 | M_UPM1; + +/** use 5-bit character size */ +static const uint8_t SP_5_BIT_CHAR = 0; +/** use 6-bit character size */ +static const uint8_t SP_6_BIT_CHAR = M_UCSZ0; +/** use 7-bit character size */ +static const uint8_t SP_7_BIT_CHAR = M_UCSZ1; +/** use 8-bit character size */ +static const uint8_t SP_8_BIT_CHAR = M_UCSZ0 | M_UCSZ1; +/** 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 */ +static const uint8_t SP_FRAMING_ERROR = M_FE; +/** USART RX data overrun error bit */ +static const uint8_t SP_RX_DATA_OVERRUN = M_DOR; +/** USART parity error bit */ +static const uint8_t SP_PARITY_ERROR = M_UPE; +/** 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 */ +static const uint8_t SP_RX_BUF_OVERRUN = 1; +//------------------------------------------------------------------------------ +/** + * \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 */ +}; +//------------------------------------------------------------------------------ +/** + * Pointers to USART registers. This static const array allows the compiler + * to generate very efficient code if the array index is a constant. + */ +static const UsartRegister usart[] = { +#ifdef UCSR0A + {&UCSR0A, &UCSR0B, &UCSR0C, &UBRR0L, &UBRR0H, &UDR0}, +#elif defined(UCSRA) + {&UCSRA, &UCSRB, &UCSRC, &UBRRL, &UBRRH, &UDR}, +#else // UCSR0A + {0, 0, 0, 0, 0, 0}, +#endif // UCSR0A + +#ifdef UCSR1A + {&UCSR1A, &UCSR1B, &UCSR1C, &UBRR1L, &UBRR1H, &UDR1}, +#else // UCSR1A + {0, 0, 0, 0, 0, 0}, +#endif // UCSR1A + +#ifdef UCSR2A + {&UCSR2A, &UCSR2B, &UCSR2C, &UBRR2L, &UBRR2H, &UDR2}, +#else // UCSR2A + {0, 0, 0, 0, 0, 0}, +#endif // UCSR2A + +#ifdef UCSR3A + {&UCSR3A, &UCSR3B, &UCSR3C, &UBRR3L, &UBRR3H, &UDR3} +#else // UCSR3A + {0, 0, 0, 0, 0, 0} +#endif // UCSR3A +}; +//------------------------------------------------------------------------------ +/** + * \class SerialRingBuffer + * \brief ring buffer for RX and TX data + */ +class SerialRingBuffer { + public: + /** Define type for buffer indices */ +#if ALLOW_LARGE_BUFFERS + typedef uint16_t buf_size_t; +#else // ALLOW_LARGE_BUFFERS + typedef uint8_t buf_size_t; +#endif // ALLOW_LARGE_BUFFERS + int available(); + /** \return true if the ring buffer is empty else false */ + bool empty() {return head_ == tail_;} + void flush(); + bool get(uint8_t* b); + buf_size_t get(uint8_t* b, buf_size_t n); + void init(uint8_t* b, buf_size_t s); + int peek(); + bool put(uint8_t b); + buf_size_t put(const uint8_t* b, buf_size_t n); + buf_size_t put_P(PGM_P b, buf_size_t n); + private: + uint8_t* buf_; /**< Pointer to start of buffer. */ + volatile buf_size_t head_; /**< Index to next empty location. */ + volatile buf_size_t tail_; /**< Index to last entry if head_ != tail_. */ + buf_size_t size_; /**< Size of the buffer. Capacity is size -1. */ +}; +//------------------------------------------------------------------------------ +/** RX ring buffers */ +extern SerialRingBuffer rxRingBuf[]; +/** TX ring buffers */ +extern SerialRingBuffer txRingBuf[]; +/** RX error bits */ +extern uint8_t rxErrorBits[]; +//------------------------------------------------------------------------------ +/** 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 + */ +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 + */ +uint8_t badTxBufSize(void) + __attribute__((error("TX buffer size too large"))); +//------------------------------------------------------------------------------ +/** + * \class SerialPort + * \brief class for avr hardware USART ports + */ +template +class SerialPort : public Stream { + public: + //---------------------------------------------------------------------------- + SerialPort() { + if (PortNumber >= SERIAL_PORT_COUNT) badPortNumber(); + if (sizeof(SerialRingBuffer::buf_size_t) == 1) { + 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 + * the serial port. + */ + int available(void) { + if (!RxBufSize) { + return *usart[PortNumber].ucsra & M_RXC ? 1 : 0; + } else { + return rxRingBuf[PortNumber].available(); + } + } + //---------------------------------------------------------------------------- + /** + * 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 + * OR of values from the following list. Choose one value for stop bit, + * parity, and character size. + * + * 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; + + // disable USART interrupts. Set UCSRB to reset values. + *usart[PortNumber].ucsrb = 0; + + // 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. + *usart[PortNumber].ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } else { + *usart[PortNumber].ucsra = M_U2X; + baud_setting = (F_CPU / 4 / baud - 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; + + // enable RX and TX + uint8_t bits = M_TXEN | M_RXEN; + + // enable receive interrupt if buffered + if (RxBufSize) bits |= M_RXCIE; + *usart[PortNumber].ucsrb = bits; + } + //---------------------------------------------------------------------------- + #if ENABLE_RX_ERROR_CHECKING + /** clear RX error bits */ + void clearRxError() {rxErrorBits[PortNumber] = 0;} + /** \return RX error bits */ + uint8_t getRxError() {return rxErrorBits[PortNumber];} + #endif // ENABLE_RX_ERROR_CHECKING + //---------------------------------------------------------------------------- + /** + * Disables serial communication, allowing the RX and TX pins to be used for + * general input and output. To re-enable serial communication, + * call SerialPort::begin(). + */ + void end() { + // wait for transmission of outgoing data + flushTx(); + // disable USART + cli(); + *usart[PortNumber].ucsrb &= ~(M_RXEN | M_TXEN | M_RXCIE | M_UDRIE); + sei(); + // clear any received data + flushRx(); + } + //---------------------------------------------------------------------------- + /** + * 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. + */ + void flushRx() { + if (RxBufSize) { + rxRingBuf[PortNumber].flush(); + } else { + uint8_t b; + while (*usart[PortNumber].ucsra & M_RXC) b = *usart[PortNumber].udr; + } + } + //---------------------------------------------------------------------------- + /** + * Waits for the transmission of outgoing serial data to complete. + */ + void flushTx() { + if (TxBufSize) { + while (!txRingBuf[PortNumber].empty()) {} + } + } + //---------------------------------------------------------------------------- + /** + * \return the first byte of incoming serial data available or + * -1 if no data is available. Peek() always return -1 for unbuffered RX. + */ + int peek(void) { + return RxBufSize ? rxRingBuf[PortNumber].peek() : -1; + } + //---------------------------------------------------------------------------- + /** + * Read incoming serial data. + * + * \return the first byte of incoming serial data available + * or -1 if no data is available + */ + __attribute__((noinline)) + int read() { + if (!RxBufSize) { + uint8_t s = *usart[PortNumber].ucsra; + #if ENABLE_RX_ERROR_CHECKING + rxErrorBits[PortNumber] |= s & SP_UCSRA_ERROR_MASK; + #endif // ENABLE_RX_ERROR_CHECKING + return s & M_RXC ? *usart[PortNumber].udr : -1; + } else { + uint8_t b; + return rxRingBuf[PortNumber].get(&b) ? b : -1; + } + } + //---------------------------------------------------------------------------- + /** + * 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 + */ + __attribute__((noinline)) + size_t read(uint8_t* b, size_t n) { + uint8_t* limit = b + n; + uint8_t* p = b; + if (RxBufSize) { + while (p < limit && !rxRingBuf[PortNumber].empty()) { + size_t nr = limit - p; + 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(); + if (rb < 0) break; + *p++ = rb; + } + } + return p - b; + } + //---------------------------------------------------------------------------- + /** + * Write binary data to the serial port. + * + * \param[in] b byte to be written. + * \return 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 + while (!txRingBuf[PortNumber].put(b)) {} + // enable interrupts + *usart[PortNumber].ucsrb |= M_UDRIE; + } + #if ARDUINO > 99 + return 1; + #endif // ARDUINO > 99 + } + //---------------------------------------------------------------------------- + /** 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 + * + * \param[in] s string to be written. + * \return 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 + */ + __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 { + size_t w = n; + while (w) { + 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 + */ + __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; + 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 + * + * \param[in] s string to be written. + * \return 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 + */ + __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 { + size_t w = n; + while (w) { + 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 + *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 + */ + __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 + //---------------------------------------------------------------------------- + private: + // RX buffer with a capacity of RxBufSize. + uint8_t rxBuffer_[RxBufSize + 1]; + // TX buffer with a capacity of TxBufSize + uint8_t txBuffer_[TxBufSize + 1]; +}; +//------------------------------------------------------------------------------ +#endif // SerialPort_h diff --git a/required_libraries/SerialPort/examples/ArduinoSize/ArduinoSize.pde b/required_libraries/SerialPort/examples/ArduinoSize/ArduinoSize.pde new file mode 100644 index 0000000..f8894ad --- /dev/null +++ b/required_libraries/SerialPort/examples/ArduinoSize/ArduinoSize.pde @@ -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/required_libraries/SerialPort/examples/ArduinoSize/FreeRam.h b/required_libraries/SerialPort/examples/ArduinoSize/FreeRam.h new file mode 100644 index 0000000..b03537c --- /dev/null +++ b/required_libraries/SerialPort/examples/ArduinoSize/FreeRam.h @@ -0,0 +1,15 @@ +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; +} diff --git a/required_libraries/SerialPort/examples/ArduinoTest/ArduinoTest.pde b/required_libraries/SerialPort/examples/ArduinoTest/ArduinoTest.pde new file mode 100644 index 0000000..7b23808 --- /dev/null +++ b/required_libraries/SerialPort/examples/ArduinoTest/ArduinoTest.pde @@ -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/required_libraries/SerialPort/examples/BufferedSize/BufferedSize.pde b/required_libraries/SerialPort/examples/BufferedSize/BufferedSize.pde new file mode 100644 index 0000000..6f83d36 --- /dev/null +++ b/required_libraries/SerialPort/examples/BufferedSize/BufferedSize.pde @@ -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/required_libraries/SerialPort/examples/BufferedSize/FreeRam.h b/required_libraries/SerialPort/examples/BufferedSize/FreeRam.h new file mode 100644 index 0000000..b03537c --- /dev/null +++ b/required_libraries/SerialPort/examples/BufferedSize/FreeRam.h @@ -0,0 +1,15 @@ +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; +} diff --git a/required_libraries/SerialPort/examples/BufferedTest/BufferedTest.pde b/required_libraries/SerialPort/examples/BufferedTest/BufferedTest.pde new file mode 100644 index 0000000..225d888 --- /dev/null +++ b/required_libraries/SerialPort/examples/BufferedTest/BufferedTest.pde @@ -0,0 +1,24 @@ +#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/required_libraries/SerialPort/examples/HelloWorld/HelloWorld.pde b/required_libraries/SerialPort/examples/HelloWorld/HelloWorld.pde new file mode 100644 index 0000000..6012eb0 --- /dev/null +++ b/required_libraries/SerialPort/examples/HelloWorld/HelloWorld.pde @@ -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/required_libraries/SerialPort/examples/MegaTest/MegaTest.pde b/required_libraries/SerialPort/examples/MegaTest/MegaTest.pde new file mode 100644 index 0000000..a536c5e --- /dev/null +++ b/required_libraries/SerialPort/examples/MegaTest/MegaTest.pde @@ -0,0 +1,41 @@ +// Test all ports on the Mega +// +// place loopback jumpers, RX connected to TX, +// on ports 1, 2, and 3. +// +#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/required_libraries/SerialPort/examples/MegaTestArduino/MegaTestArduino.pde b/required_libraries/SerialPort/examples/MegaTestArduino/MegaTestArduino.pde new file mode 100644 index 0000000..5c5fdbb --- /dev/null +++ b/required_libraries/SerialPort/examples/MegaTestArduino/MegaTestArduino.pde @@ -0,0 +1,27 @@ +// Test all ports on the Mega +// +// place loopback jumpers, RX connected to TX, +// on ports 1, 2, and 3. +// +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/required_libraries/SerialPort/examples/ReadWriteTest/ReadWriteTest.pde b/required_libraries/SerialPort/examples/ReadWriteTest/ReadWriteTest.pde new file mode 100644 index 0000000..c7d2246 --- /dev/null +++ b/required_libraries/SerialPort/examples/ReadWriteTest/ReadWriteTest.pde @@ -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/required_libraries/SerialPort/examples/UnbufferedSize/FreeRam.h b/required_libraries/SerialPort/examples/UnbufferedSize/FreeRam.h new file mode 100644 index 0000000..b03537c --- /dev/null +++ b/required_libraries/SerialPort/examples/UnbufferedSize/FreeRam.h @@ -0,0 +1,15 @@ +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; +} diff --git a/required_libraries/SerialPort/examples/UnbufferedSize/UnbufferedSize.pde b/required_libraries/SerialPort/examples/UnbufferedSize/UnbufferedSize.pde new file mode 100644 index 0000000..80f88fd --- /dev/null +++ b/required_libraries/SerialPort/examples/UnbufferedSize/UnbufferedSize.pde @@ -0,0 +1,15 @@ +// 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 +// +#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/required_libraries/SerialPort/examples/UnbufferedTest/UnbufferedTest.pde b/required_libraries/SerialPort/examples/UnbufferedTest/UnbufferedTest.pde new file mode 100644 index 0000000..9043410 --- /dev/null +++ b/required_libraries/SerialPort/examples/UnbufferedTest/UnbufferedTest.pde @@ -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/required_libraries/SerialPort/examples/WriteFlash/WriteFlash.pde b/required_libraries/SerialPort/examples/WriteFlash/WriteFlash.pde new file mode 100644 index 0000000..72544da --- /dev/null +++ b/required_libraries/SerialPort/examples/WriteFlash/WriteFlash.pde @@ -0,0 +1,19 @@ +// test write() for a flash string +#include + +SerialPort<0, 0, 32> port; + +void setup(void) { + port.begin(115200); + + 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); + } +} +void loop(void) {} diff --git a/required_libraries/SerialPort/readme.md b/required_libraries/SerialPort/readme.md new file mode 100644 index 0000000..77f53ba --- /dev/null +++ b/required_libraries/SerialPort/readme.md @@ -0,0 +1,7 @@ +SerialPort is a library from [Bill Greiman’s beta library](https://code.google.com/p/sdfatlib/downloads/list). + +OpenLog currently uses the 20120106 version. + +Unzip ‘SerialPortBeta20120106.zip’ and ‘SdFatBeta20120108.zip’ to Arduino’s “libraries” directory (usually something like C:\arduino-1.0\libraries) and close and restart Arduino. To verify these are installed correctly, you should now see ‘SerialPort’ and ‘SdFat’ under the File->Examples menu. + +For more information about installing Arduino libraries see the [SparkFun Learn tutorial](https://learn.sparkfun.com/tutorials/installing-an-arduino-library). \ No newline at end of file