aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtsushi Saitoh <lynxeyed@xj9.so-net.ne.jp>2012-03-19 18:41:19 -0700
committerAtsushi Saitoh <lynxeyed@xj9.so-net.ne.jp>2012-03-19 18:41:19 -0700
commit0dab4b05f8a80096339ca6aced059c024798c97a (patch)
treeda2676f36510bde8fbd7512c775f7010a1d22c8d
parent7f6b217b9f31953e40edbb6a9177d69f604a2a23 (diff)
parent85e9afba864035c3c7a583e8e54a7023aa0f5306 (diff)
Merge pull request #3 from nucho/myFunction
Added SoftwareSerial
-rw-r--r--src/core/Print.cpp15
-rw-r--r--src/core/Print.h5
-rw-r--r--src/core/SoftwareSerial.cpp311
-rw-r--r--src/core/SoftwareSerial.h104
4 files changed, 434 insertions, 1 deletions
diff --git a/src/core/Print.cpp b/src/core/Print.cpp
index ab58b9f..d2c3848 100644
--- a/src/core/Print.cpp
+++ b/src/core/Print.cpp
@@ -107,3 +107,18 @@ void Print::println(void)
return;
}
+void Print::print(const char c)
+{
+ write(c);
+ return;
+}
+
+void Print::println(const char c)
+{
+ write(c);
+ println();
+ return;
+}
+
+
+
diff --git a/src/core/Print.h b/src/core/Print.h
index 3c83abe..91a7482 100644
--- a/src/core/Print.h
+++ b/src/core/Print.h
@@ -32,9 +32,12 @@ public:
void write(const char *s,int length);
void write(const char *s) { return write((const char *)s, strlen(s)); }
- virtual void println(void);
+ void print(const char c);
void print(const char *s);
void print(int val, RADIX_FORMAT format);
+
+ virtual void println(void);
+ void println(const char c);
void println(const char *s);
void println(int val, RADIX_FORMAT format);
};
diff --git a/src/core/SoftwareSerial.cpp b/src/core/SoftwareSerial.cpp
new file mode 100644
index 0000000..a49dc4b
--- /dev/null
+++ b/src/core/SoftwareSerial.cpp
@@ -0,0 +1,311 @@
+/*
+ * This class is porting arduino's SoftwareSerial for eXodusino
+ *
+ * Created on: 2012/03/17
+ * @author nucho
+ */
+
+/*
+ SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
+ Multi-instance software serial library for Arduino/Wiring
+ -- Interrupt-driven receive and other improvements by ladyada
+ (http://ladyada.net)
+ -- Tuning, circular buffer, derivation from class Print/Stream,
+ multi-instance support, porting to 8MHz processors,
+ various optimizations, PROGMEM delay tables, inverse logic and
+ direct port writing by Mikal Hart (http://www.arduiniana.org)
+ -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
+ -- 20MHz processor support by Garrett Mace (http://www.macetech.com)
+ -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ The latest version of this library can always be found at
+ http://arduiniana.org.
+ */
+
+#include "SoftwareSerial.h"
+#include "gpio.h"
+#include "delay.h"
+//
+// Lookup table
+//
+typedef struct _DELAY_TABLE {
+ long baud;
+ unsigned short rx_delay_centering;
+ unsigned short rx_delay_intrabit;
+ unsigned short rx_delay_stopbit;
+ unsigned short tx_delay;
+} DELAY_TABLE;
+
+static const DELAY_TABLE table[] = {
+// baud rxcenter rxintra rxstop tx
+ { 38400, 11, 23, 23, 23, },//no support
+ { 19200, 23, 47, 47, 49, },//no support
+ { 9600, 50,100, 100, 100, },
+ { 4800, 101, 202, 202, 202, },
+};
+
+
+//
+// Debugging
+//
+// This function generates a brief pulse
+// for debugging or measuring on an oscilloscope.
+inline void DebugPulse(uint8_t pin, uint8_t count) {
+ //#if _DEBUG
+ // volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));
+ //
+ // uint8_t val = *pport;
+ // while (count--)
+ // {
+ // *pport = val | digitalPinToBitMask(pin);
+ // *pport = val;
+ // }
+ //#endif
+}
+
+//
+// Statics
+//
+SoftwareSerial *SoftwareSerial::active_object = 0;
+char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
+volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
+volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;
+
+//
+// Private methods
+//
+
+// This function sets the current object as the "listening"
+// one and returns true if it replaces another
+bool SoftwareSerial::listen() {
+ if (active_object != this) {
+ _buffer_overflow = false;
+
+ _receive_buffer_head = _receive_buffer_tail = 0;
+ active_object = this;
+ return true;
+ }
+
+ return false;
+}
+
+//
+// The receive routine called by the interrupt handler
+//
+void SoftwareSerial::recv() {
+ uint8_t d = 0;
+
+ // If RX line is high, then we don't see any start bit
+ // so interrupt is probably not for us
+ if (_inverse_logic ? digitalRead(_receivePin) : !digitalRead(_receivePin)) {
+ // Wait approximately 1/2 of a bit width to "center" the sample
+ delayMicroseconds(_rx_delay_centering);
+
+ DebugPulse(4, 1);
+
+ // Read each of the 8 bits
+ for (uint8_t i = 0x1; i; i <<= 1) {
+ delayMicroseconds(_rx_delay_intrabit);
+ DebugPulse(4, 1);
+ uint8_t noti = ~i;
+ if (digitalRead(_receivePin))
+ d |= i;
+ else
+ // else clause added to ensure function timing is ~balanced
+ d &= noti;
+ }
+
+ // skip the stop bit
+ delayMicroseconds(_rx_delay_stopbit);
+ DebugPulse(4, 1);
+
+ if (_inverse_logic)
+ d = ~d;
+
+ // if buffer full, set the overflow flag and return
+ if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF
+ != _receive_buffer_head) {
+ // save new data in buffer: tail points to where byte goes
+ _receive_buffer[_receive_buffer_tail] = d; // save new byte
+ _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
+ } else {
+ _buffer_overflow = true;
+ }
+ }
+}
+// Interrupt handling
+//
+
+/* static */
+inline void SoftwareSerial::handle_interrupt() {
+ if (active_object) {
+ active_object->recv();
+ }
+}
+
+//
+// Constructor
+//
+SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin,
+ bool inverse_logic /* = false */) :
+ _rx_delay_centering(0), _rx_delay_intrabit(0), _rx_delay_stopbit(0),
+ _tx_delay(0), _buffer_overflow(false),
+ _inverse_logic(inverse_logic) {
+ setTX(transmitPin);
+ setRX(receivePin);
+}
+
+//
+// Destructor
+//
+SoftwareSerial::~SoftwareSerial() {
+ end();
+}
+
+void SoftwareSerial::setTX(uint8_t tx) {
+ if (tx >= 0) {
+ pinMode(tx, OUTPUT);
+ digitalWrite(tx, HIGH);
+ }
+ _transmitPin = tx;
+}
+
+void SoftwareSerial::setRX(uint8_t rx) {
+ if (rx >= 0) {
+ if (!_inverse_logic) {
+ //TODO:pin pullup
+ } else {
+ //TODO:pin pulldown
+ }
+ }
+ _receivePin = rx;
+}
+
+//
+// Public methods
+//
+
+void SoftwareSerial::begin(long speed) {
+ _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay
+ = 0;
+
+ for (unsigned i = 0; i < sizeof(table) / sizeof(table[0]); ++i) {
+ long baud = table[i].baud;
+ if (baud == speed) {
+ _rx_delay_centering = table[i].rx_delay_centering;
+ _rx_delay_intrabit = table[i].rx_delay_intrabit;
+ _rx_delay_stopbit = table[i].rx_delay_stopbit;
+ _tx_delay = table[i].tx_delay;
+ break;
+ }
+ }
+ // Set up RX interrupts, but only if we have a valid RX baud rate
+ if (_rx_delay_stopbit && _receivePin > 0) {
+ attachInterrupt(_receivePin, SoftwareSerial::handle_interrupt, FALLING);
+ delayMicroseconds(_tx_delay);// if we were low this establishes the end
+ }
+
+ listen();
+}
+
+void SoftwareSerial::end() {
+ if (_receivePin > 0) {
+ detachInterrupt(_receivePin);
+ }
+}
+
+// Read data from buffer
+int SoftwareSerial::read() {
+ if (!isListening())
+ return -1;
+
+ // Empty buffer?
+ if (_receive_buffer_head == _receive_buffer_tail)
+ return -1;
+
+ // Read from "head"
+ uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte
+ _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
+ return d;
+}
+
+int SoftwareSerial::available() {
+ if (!isListening())
+ return 0;
+
+ return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head)
+ % _SS_MAX_RX_BUFF;
+}
+
+void SoftwareSerial::write(const char c) {
+ if (_tx_delay == 0) {
+ return;
+ }
+ if (_transmitPin < 0) {
+ return;
+ }
+
+ // Write the start bit
+ digitalWrite(_transmitPin, _inverse_logic ? HIGH : LOW);
+ delayMicroseconds(_tx_delay);
+
+ // Write each of the 8 bits
+ if (_inverse_logic) {
+ for (uint8_t mask = 0x01; mask; mask <<= 1) {
+ if (c & mask) // choose bit
+ digitalWrite(_transmitPin, LOW); // send 1
+ else
+ digitalWrite(_transmitPin, HIGH); // send 0
+
+ delayMicroseconds(_tx_delay);
+ }
+
+ digitalWrite(_transmitPin, LOW); // restore pin to natural state
+ } else {
+ for (uint8_t mask = 0x01; mask; mask <<= 1) {
+ if (c & mask) // choose bit
+ digitalWrite(_transmitPin, HIGH); // send 1
+ else
+ digitalWrite(_transmitPin, LOW); // send 0
+
+ delayMicroseconds(_tx_delay);
+ }
+
+ digitalWrite(_transmitPin, HIGH); // restore pin to natural state
+ }
+
+ delayMicroseconds(_tx_delay);
+}
+
+void SoftwareSerial::flush() {
+ if (!isListening())
+ return;
+
+ _receive_buffer_head = _receive_buffer_tail = 0;
+}
+
+int SoftwareSerial::peek() {
+ if (!isListening())
+ return -1;
+
+ // Empty buffer?
+ if (_receive_buffer_head == _receive_buffer_tail)
+ return -1;
+
+ // Read from "head"
+ return _receive_buffer[_receive_buffer_head];
+}
diff --git a/src/core/SoftwareSerial.h b/src/core/SoftwareSerial.h
new file mode 100644
index 0000000..fd6287d
--- /dev/null
+++ b/src/core/SoftwareSerial.h
@@ -0,0 +1,104 @@
+/*
+ * This class is porting arduino's SoftwareSerial for eXodusino
+ *
+ * Created on: 2012/03/17
+ * @author nucho
+ */
+
+/*
+ SoftwareSerial.h (formerly NewSoftSerial.h) -
+ Multi-instance software serial library for Arduino/Wiring
+ -- Interrupt-driven receive and other improvements by ladyada
+ (http://ladyada.net)
+ -- Tuning, circular buffer, derivation from class Print/Stream,
+ multi-instance support, porting to 8MHz processors,
+ various optimizations, PROGMEM delay tables, inverse logic and
+ direct port writing by Mikal Hart (http://www.arduiniana.org)
+ -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
+ -- 20MHz processor support by Garrett Mace (http://www.macetech.com)
+ -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ The latest version of this library can always be found at
+ http://arduiniana.org.
+ */
+
+#ifndef SoftwareSerial_h
+#define SoftwareSerial_h
+
+#include "Print.h"
+#include "LPC11xx.h"
+
+/******************************************************************************
+ * Definitions
+ ******************************************************************************/
+#define _SS_MAX_RX_BUFF 64 // RX buffer size
+class SoftwareSerial: public Print {
+private:
+ // per object data
+ uint8_t _receivePin;
+ uint8_t _transmitPin;
+
+ uint16_t _rx_delay_centering;
+ uint16_t _rx_delay_intrabit;
+ uint16_t _rx_delay_stopbit;
+ uint16_t _tx_delay;
+
+ bool _buffer_overflow :1;
+ bool _inverse_logic :1;
+
+ // static data
+ static char _receive_buffer[_SS_MAX_RX_BUFF];
+ static volatile uint8_t _receive_buffer_tail;
+ static volatile uint8_t _receive_buffer_head;
+ static SoftwareSerial *active_object;
+
+ // private methods
+ void recv();
+ void setTX(uint8_t transmitPin);
+ void setRX(uint8_t receivePin);
+
+public:
+ // public methods
+ SoftwareSerial(uint8_t receivePin, uint8_t transmitPin,
+ bool inverse_logic = false);
+
+ ~SoftwareSerial();
+ void begin(long speed);
+ bool listen();
+ void end();
+ bool isListening() {
+ return this == active_object;
+ }
+ bool overflow() {
+ bool ret = _buffer_overflow;
+ _buffer_overflow = false;
+ return ret;
+ }
+ int peek();
+
+ virtual void write(const char c);
+ int read();
+ int available();
+ void flush();
+
+ using Print::write;// pull in write(buf, size) from Print
+
+ // public only for easy access by interrupt handlers
+ static inline void handle_interrupt();
+};
+
+#endif