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