add HardwareSerial and SoftwareSerial for Re-ARM.
HardwareSerial has been tested on Uart0 (debug header) and Uart3 (i2c connector) Software Serial has been tested to work bi-directionally at 9600 and 115200 using pins 6 and 63 on J5, and unidirectionally (write only) at 250000. The code used to test was Teemuatlut's tmc2208 patch, and a few small changes to main used to echo recieved chars back to a host pc.2.0.x
parent
01fb45b4f8
commit
18f97c4013
@ -0,0 +1,319 @@
|
||||
/*
|
||||
Stream.cpp - adds parsing methods to Stream class
|
||||
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||
|
||||
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
|
||||
|
||||
Created July 2011
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
|
||||
findMulti/findUntil routines written by Jim Leonard/Xuth
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "../../../../src/HAL/HAL_LPC1768/arduino.h"
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
|
||||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
||||
|
||||
// private method to read stream with timeout
|
||||
int Stream::timedRead()
|
||||
{
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = read();
|
||||
if (c >= 0) return c;
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// private method to peek stream with timeout
|
||||
int Stream::timedPeek()
|
||||
{
|
||||
int c;
|
||||
_startMillis = millis();
|
||||
do {
|
||||
c = peek();
|
||||
if (c >= 0) return c;
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// returns peek of the next digit in the stream or -1 if timeout
|
||||
// discards non-numeric characters
|
||||
int Stream::peekNextDigit()
|
||||
{
|
||||
int c;
|
||||
while (1) {
|
||||
c = timedPeek();
|
||||
if (c < 0) return c; // timeout
|
||||
if (c == '-') return c;
|
||||
if (c >= '0' && c <= '9') return c;
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(char *target)
|
||||
{
|
||||
return findUntil(target, strlen(target), NULL, 0);
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of given length is found
|
||||
// returns true if target string is found, false if timed out
|
||||
bool Stream::find(char *target, size_t length)
|
||||
{
|
||||
return findUntil(target, length, NULL, 0);
|
||||
}
|
||||
|
||||
// as find but search ends if the terminator string is found
|
||||
bool Stream::findUntil(char *target, char *terminator)
|
||||
{
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of the given length is found
|
||||
// search terminated if the terminator string is found
|
||||
// returns true if target string is found, false if terminated or timed out
|
||||
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
|
||||
{
|
||||
if (terminator == NULL) {
|
||||
MultiTarget t[1] = {{target, targetLen, 0}};
|
||||
return findMulti(t, 1) == 0 ? true : false;
|
||||
} else {
|
||||
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
||||
return findMulti(t, 2) == 0 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// function is terminated by the first character that is not a digit.
|
||||
long Stream::parseInt()
|
||||
{
|
||||
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||
}
|
||||
|
||||
// as above but a given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
long Stream::parseInt(char skipChar)
|
||||
{
|
||||
bool isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0)
|
||||
return 0; // zero returned if timeout
|
||||
|
||||
do{
|
||||
if(c == skipChar)
|
||||
; // ignore this charactor
|
||||
else if(c == '-')
|
||||
isNegative = true;
|
||||
else if(c >= '0' && c <= '9') // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
}
|
||||
while( (c >= '0' && c <= '9') || c == skipChar );
|
||||
|
||||
if(isNegative)
|
||||
value = -value;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat()
|
||||
{
|
||||
return parseFloat(NO_SKIP_CHAR);
|
||||
}
|
||||
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
float Stream::parseFloat(char skipChar){
|
||||
bool isNegative = false;
|
||||
bool isFraction = false;
|
||||
long value = 0;
|
||||
char c;
|
||||
float fraction = 1.0;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0)
|
||||
return 0; // zero returned if timeout
|
||||
|
||||
do{
|
||||
if(c == skipChar)
|
||||
; // ignore
|
||||
else if(c == '-')
|
||||
isNegative = true;
|
||||
else if (c == '.')
|
||||
isFraction = true;
|
||||
else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
if(isFraction)
|
||||
fraction *= 0.1;
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
}
|
||||
while( (c >= '0' && c <= '9') || c == '.' || c == skipChar );
|
||||
|
||||
if(isNegative)
|
||||
value = -value;
|
||||
if(isFraction)
|
||||
return value * fraction;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (count < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0) break;
|
||||
*buffer++ = (char)c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// as readBytes with terminator character
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
||||
{
|
||||
if (length < 1) return 0;
|
||||
size_t index = 0;
|
||||
while (index < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0 || c == terminator) break;
|
||||
*buffer++ = (char)c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
String Stream::readString()
|
||||
{
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0)
|
||||
{
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String Stream::readStringUntil(char terminator)
|
||||
{
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0 && c != terminator)
|
||||
{
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
|
||||
// any zero length target string automatically matches and would make
|
||||
// a mess of the rest of the algorithm.
|
||||
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||
if (t->len <= 0)
|
||||
return t - targets;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int c = timedRead();
|
||||
if (c < 0)
|
||||
return -1;
|
||||
|
||||
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||
// the simple case is if we match, deal with that first.
|
||||
if (c == t->str[t->index]) {
|
||||
if (++t->index == t->len)
|
||||
return t - targets;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not we need to walk back and see if we could have matched further
|
||||
// down the stream (ie '1112' doesn't match the first position in '11112'
|
||||
// but it will match the second position so we can't just reset the current
|
||||
// index to 0 when we find a mismatch.
|
||||
if (t->index == 0)
|
||||
continue;
|
||||
|
||||
int origIndex = t->index;
|
||||
do {
|
||||
--t->index;
|
||||
// first check if current char works against the new current index
|
||||
if (c != t->str[t->index])
|
||||
continue;
|
||||
|
||||
// if it's the only char then we're good, nothing more to check
|
||||
if (t->index == 0) {
|
||||
t->index++;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise we need to check the rest of the found string
|
||||
int diff = origIndex - t->index;
|
||||
size_t i;
|
||||
for (i = 0; i < t->index; ++i) {
|
||||
if (t->str[i] != t->str[i + diff])
|
||||
break;
|
||||
}
|
||||
|
||||
// if we successfully got through the previous loop then our current
|
||||
// index is good.
|
||||
if (i == t->index) {
|
||||
t->index++;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise we just try the next index
|
||||
} while (t->index);
|
||||
}
|
||||
}
|
||||
// unreachable
|
||||
return -1;
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||
|
||||
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
|
||||
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
*/
|
||||
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
#include "WString.h"
|
||||
|
||||
// compatability macros for testing
|
||||
/*
|
||||
#define getInt() parseInt()
|
||||
#define getInt(skipChar) parseInt(skipchar)
|
||||
#define getFloat() parseFloat()
|
||||
#define getFloat(skipChar) parseFloat(skipChar)
|
||||
#define getString( pre_string, post_string, buffer, length)
|
||||
readBytesBetween( pre_string, terminator, buffer, length)
|
||||
*/
|
||||
|
||||
class Stream : public Print
|
||||
{
|
||||
protected:
|
||||
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
||||
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
|
||||
Stream() {_timeout=1000;}
|
||||
|
||||
// parsing methods
|
||||
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
|
||||
bool find(char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target) { return find ((char *)target); }
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
|
||||
bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found
|
||||
bool find(uint8_t *target, size_t length) { return find ((char *)target, length); }
|
||||
// returns true if target string is found, false if timed out
|
||||
|
||||
bool find(char target) { return find (&target, 1); }
|
||||
|
||||
bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); }
|
||||
|
||||
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); }
|
||||
|
||||
|
||||
long parseInt(); // returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// integer is terminated by the first character that is not a digit.
|
||||
|
||||
float parseFloat(); // float version of parseInt
|
||||
|
||||
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
|
||||
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character
|
||||
size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); }
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
// Arduino String functions to be added here
|
||||
String readString();
|
||||
String readStringUntil(char terminator);
|
||||
|
||||
protected:
|
||||
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
|
||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||
|
||||
struct MultiTarget {
|
||||
const char *str; // string you're searching for
|
||||
size_t len; // length of string you're searching for
|
||||
size_t index; // index used by the search routine.
|
||||
};
|
||||
|
||||
// This allows you to search for an arbitrary number of strings.
|
||||
// Returns index of the target that is found first or -1 if timeout occurs.
|
||||
int findMulti(struct MultiTarget *targets, int tCount);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
WString.h - String library for Wiring & Arduino
|
||||
...mostly rewritten by Paul Stoffregen...
|
||||
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
||||
Copyright 2011, Paul Stoffregen, paul@pjrc.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
|
||||
*/
|
||||
|
||||
#ifndef String_class_h
|
||||
#define String_class_h
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
//#include <avr/pgmspace.h>
|
||||
|
||||
// When compiling programs with this class, the following gcc parameters
|
||||
// dramatically increase performance and memory (RAM) efficiency, typically
|
||||
// with little or no increase in code size.
|
||||
// -felide-constructors
|
||||
// -std=c++0x
|
||||
|
||||
class __FlashStringHelper;
|
||||
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
|
||||
|
||||
// An inherited class for holding the result of a concatenation. These
|
||||
// result objects are assumed to be writable by subsequent concatenations.
|
||||
class StringSumHelper;
|
||||
|
||||
// The string class
|
||||
class String
|
||||
{
|
||||
// use a function pointer to allow for "if (s)" without the
|
||||
// complications of an operator bool(). for more information, see:
|
||||
// http://www.artima.com/cppsource/safebool.html
|
||||
typedef void (String::*StringIfHelperType)() const;
|
||||
void StringIfHelper() const {}
|
||||
|
||||
public:
|
||||
// constructors
|
||||
// creates a copy of the initial value.
|
||||
// if the initial value is null or invalid, or if memory allocation
|
||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
#endif
|
||||
explicit String(char c);
|
||||
explicit String(unsigned char, unsigned char base=10);
|
||||
explicit String(int, unsigned char base=10);
|
||||
explicit String(unsigned int, unsigned char base=10);
|
||||
explicit String(long, unsigned char base=10);
|
||||
explicit String(unsigned long, unsigned char base=10);
|
||||
explicit String(float, unsigned char decimalPlaces=2);
|
||||
explicit String(double, unsigned char decimalPlaces=2);
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
// return true on success, false on failure (in which case, the string
|
||||
// is left unchanged). reserve(0), if successful, will validate an
|
||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const {return len;}
|
||||
|
||||
// creates a copy of the assigned value. if the value is null or
|
||||
// invalid, or if the memory allocation fails, the string will be
|
||||
// marked as invalid ("if (s)" will be false).
|
||||
String & operator = (const String &rhs);
|
||||
String & operator = (const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *str);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String & operator = (String &&rval);
|
||||
String & operator = (StringSumHelper &&rval);
|
||||
#endif
|
||||
|
||||
// concatenate (works w/ built-in types)
|
||||
|
||||
// returns true on success, false on failure (in which case, the string
|
||||
// is left unchanged). if the argument is null or invalid, the
|
||||
// concatenation is considered unsucessful.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(char c);
|
||||
unsigned char concat(unsigned char c);
|
||||
unsigned char concat(int num);
|
||||
unsigned char concat(unsigned int num);
|
||||
unsigned char concat(long num);
|
||||
unsigned char concat(unsigned long num);
|
||||
unsigned char concat(float num);
|
||||
unsigned char concat(double num);
|
||||
unsigned char concat(const __FlashStringHelper * str);
|
||||
|
||||
// if there's not enough memory for the concatenated value, the string
|
||||
// will be left unchanged (but this isn't signalled in any way)
|
||||
String & operator += (const String &rhs) {concat(rhs); return (*this);}
|
||||
String & operator += (const char *cstr) {concat(cstr); return (*this);}
|
||||
String & operator += (char c) {concat(c); return (*this);}
|
||||
String & operator += (unsigned char num) {concat(num); return (*this);}
|
||||
String & operator += (int num) {concat(num); return (*this);}
|
||||
String & operator += (unsigned int num) {concat(num); return (*this);}
|
||||
String & operator += (long num) {concat(num); return (*this);}
|
||||
String & operator += (unsigned long num) {concat(num); return (*this);}
|
||||
String & operator += (float num) {concat(num); return (*this);}
|
||||
String & operator += (double num) {concat(num); return (*this);}
|
||||
String & operator += (const __FlashStringHelper *str){concat(str); return (*this);}
|
||||
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
|
||||
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
|
||||
int compareTo(const String &s) const;
|
||||
unsigned char equals(const String &s) const;
|
||||
unsigned char equals(const char *cstr) const;
|
||||
unsigned char operator == (const String &rhs) const {return equals(rhs);}
|
||||
unsigned char operator == (const char *cstr) const {return equals(cstr);}
|
||||
unsigned char operator != (const String &rhs) const {return !equals(rhs);}
|
||||
unsigned char operator != (const char *cstr) const {return !equals(cstr);}
|
||||
unsigned char operator < (const String &rhs) const;
|
||||
unsigned char operator > (const String &rhs) const;
|
||||
unsigned char operator <= (const String &rhs) const;
|
||||
unsigned char operator >= (const String &rhs) const;
|
||||
unsigned char equalsIgnoreCase(const String &s) const;
|
||||
unsigned char startsWith( const String &prefix) const;
|
||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||
unsigned char endsWith(const String &suffix) const;
|
||||
|
||||
// character acccess
|
||||
char charAt(unsigned int index) const;
|
||||
void setCharAt(unsigned int index, char c);
|
||||
char operator [] (unsigned int index) const;
|
||||
char& operator [] (unsigned int index);
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
|
||||
{ getBytes((unsigned char *)buf, bufsize, index); }
|
||||
const char* c_str() const { return buffer; }
|
||||
char* begin() { return buffer; }
|
||||
char* end() { return buffer + length(); }
|
||||
const char* begin() const { return c_str(); }
|
||||
const char* end() const { return c_str() + length(); }
|
||||
|
||||
// search
|
||||
int indexOf( char ch ) const;
|
||||
int indexOf( char ch, unsigned int fromIndex ) const;
|
||||
int indexOf( const String &str ) const;
|
||||
int indexOf( const String &str, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( char ch ) const;
|
||||
int lastIndexOf( char ch, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( const String &str ) const;
|
||||
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
|
||||
String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); };
|
||||
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
|
||||
|
||||
// modification
|
||||
void replace(char find, char replace);
|
||||
void replace(const String& find, const String& replace);
|
||||
void remove(unsigned int index);
|
||||
void remove(unsigned int index, unsigned int count);
|
||||
void toLowerCase(void);
|
||||
void toUpperCase(void);
|
||||
void trim(void);
|
||||
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
double toDouble(void) const;
|
||||
|
||||
protected:
|
||||
char *buffer; // the actual char array
|
||||
unsigned int capacity; // the array length minus one (for the '\0')
|
||||
unsigned int len; // the String length (not counting the '\0')
|
||||
protected:
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
void move(String &rhs);
|
||||
#endif
|
||||
};
|
||||
|
||||
class StringSumHelper : public String
|
||||
{
|
||||
public:
|
||||
StringSumHelper(const String &s) : String(s) {}
|
||||
StringSumHelper(const char *p) : String(p) {}
|
||||
StringSumHelper(char c) : String(c) {}
|
||||
StringSumHelper(unsigned char num) : String(num) {}
|
||||
StringSumHelper(int num) : String(num) {}
|
||||
StringSumHelper(unsigned int num) : String(num) {}
|
||||
StringSumHelper(long num) : String(num) {}
|
||||
StringSumHelper(unsigned long num) : String(num) {}
|
||||
StringSumHelper(float num) : String(num) {}
|
||||
StringSumHelper(double num) : String(num) {}
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // String_class_h
|
@ -0,0 +1,636 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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 program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../macros.h"
|
||||
#include "../HAL.h"
|
||||
#include "HardwareSerial.h"
|
||||
#define UART3 3
|
||||
HardwareSerial Serial3 = HardwareSerial(UART3);
|
||||
|
||||
volatile uint32_t UART0Status, UART1Status, UART2Status, UART3Status;
|
||||
volatile uint8_t UART0TxEmpty = 1, UART1TxEmpty = 1, UART2TxEmpty=1, UART3TxEmpty=1;
|
||||
volatile uint8_t UART0Buffer[UARTRXQUEUESIZE], UART1Buffer[UARTRXQUEUESIZE], UART2Buffer[UARTRXQUEUESIZE], UART3Buffer[UARTRXQUEUESIZE];
|
||||
volatile uint32_t UART0RxQueueWritePos = 0, UART1RxQueueWritePos = 0, UART2RxQueueWritePos = 0, UART3RxQueueWritePos = 0;
|
||||
volatile uint32_t UART0RxQueueReadPos = 0, UART1RxQueueReadPos = 0, UART2RxQueueReadPos = 0, UART3RxQueueReadPos = 0;
|
||||
volatile uint8_t dummy;
|
||||
|
||||
void HardwareSerial::begin(uint32_t baudrate) {
|
||||
uint32_t Fdiv;
|
||||
uint32_t pclkdiv, pclk;
|
||||
|
||||
if ( PortNum == 0 )
|
||||
{
|
||||
LPC_PINCON->PINSEL0 &= ~0x000000F0;
|
||||
LPC_PINCON->PINSEL0 |= 0x00000050; /* RxD0 is P0.3 and TxD0 is P0.2 */
|
||||
/* By default, the PCLKSELx value is zero, thus, the PCLK for
|
||||
all the peripherals is 1/4 of the SystemFrequency. */
|
||||
/* Bit 6~7 is for UART0 */
|
||||
pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;
|
||||
switch ( pclkdiv )
|
||||
{
|
||||
case 0x00:
|
||||
default:
|
||||
pclk = SystemCoreClock/4;
|
||||
break;
|
||||
case 0x01:
|
||||
pclk = SystemCoreClock;
|
||||
break;
|
||||
case 0x02:
|
||||
pclk = SystemCoreClock/2;
|
||||
break;
|
||||
case 0x03:
|
||||
pclk = SystemCoreClock/8;
|
||||
break;
|
||||
}
|
||||
|
||||
LPC_UART0->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
|
||||
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */
|
||||
LPC_UART0->DLM = Fdiv / 256;
|
||||
LPC_UART0->DLL = Fdiv % 256;
|
||||
LPC_UART0->LCR = 0x03; /* DLAB = 0 */
|
||||
LPC_UART0->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
|
||||
|
||||
NVIC_EnableIRQ(UART0_IRQn);
|
||||
|
||||
LPC_UART0->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART0 interrupt */
|
||||
}
|
||||
else if ( PortNum == 1 )
|
||||
{
|
||||
LPC_PINCON->PINSEL4 &= ~0x0000000F;
|
||||
LPC_PINCON->PINSEL4 |= 0x0000000A; /* Enable RxD1 P2.1, TxD1 P2.0 */
|
||||
|
||||
/* By default, the PCLKSELx value is zero, thus, the PCLK for
|
||||
all the peripherals is 1/4 of the SystemFrequency. */
|
||||
/* Bit 8,9 are for UART1 */
|
||||
pclkdiv = (LPC_SC->PCLKSEL0 >> 8) & 0x03;
|
||||
switch ( pclkdiv )
|
||||
{
|
||||
case 0x00:
|
||||
default:
|
||||
pclk = SystemCoreClock/4;
|
||||
break;
|
||||
case 0x01:
|
||||
pclk = SystemCoreClock;
|
||||
break;
|
||||
case 0x02:
|
||||
pclk = SystemCoreClock/2;
|
||||
break;
|
||||
case 0x03:
|
||||
pclk = SystemCoreClock/8;
|
||||
break;
|
||||
}
|
||||
|
||||
LPC_UART1->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
|
||||
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */
|
||||
LPC_UART1->DLM = Fdiv / 256;
|
||||
LPC_UART1->DLL = Fdiv % 256;
|
||||
LPC_UART1->LCR = 0x03; /* DLAB = 0 */
|
||||
LPC_UART1->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
|
||||
|
||||
NVIC_EnableIRQ(UART1_IRQn);
|
||||
|
||||
LPC_UART1->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART1 interrupt */
|
||||
}
|
||||
else if ( PortNum == 2 )
|
||||
{
|
||||
//LPC_PINCON->PINSEL4 &= ~0x000F0000; /*Pinsel4 Bits 16-19*/
|
||||
//LPC_PINCON->PINSEL4 |= 0x000A0000; /* RxD2 is P2.9 and TxD2 is P2.8, value 10*/
|
||||
LPC_PINCON->PINSEL0 &= ~0x00F00000; /*Pinsel0 Bits 20-23*/
|
||||
LPC_PINCON->PINSEL0 |= 0x00500000; /* RxD2 is P0.11 and TxD2 is P0.10, value 01*/
|
||||
|
||||
LPC_SC->PCONP |= 1<<24; //Enable PCUART2
|
||||
/* By default, the PCLKSELx value is zero, thus, the PCLK for
|
||||
all the peripherals is 1/4 of the SystemFrequency. */
|
||||
/* Bit 6~7 is for UART3 */
|
||||
pclkdiv = (LPC_SC->PCLKSEL1 >> 16) & 0x03;
|
||||
switch ( pclkdiv )
|
||||
{
|
||||
case 0x00:
|
||||
default:
|
||||
pclk = SystemCoreClock/4;
|
||||
break;
|
||||
case 0x01:
|
||||
pclk = SystemCoreClock;
|
||||
break;
|
||||
case 0x02:
|
||||
pclk = SystemCoreClock/2;
|
||||
break;
|
||||
case 0x03:
|
||||
pclk = SystemCoreClock/8;
|
||||
break;
|
||||
}
|
||||
LPC_UART2->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
|
||||
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */
|
||||
LPC_UART2->DLM = Fdiv / 256;
|
||||
LPC_UART2->DLL = Fdiv % 256;
|
||||
LPC_UART2->LCR = 0x03; /* DLAB = 0 */
|
||||
LPC_UART2->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
|
||||
|
||||
NVIC_EnableIRQ(UART2_IRQn);
|
||||
|
||||
LPC_UART2->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART3 interrupt */
|
||||
}
|
||||
else if ( PortNum == 3 )
|
||||
{
|
||||
LPC_PINCON->PINSEL0 &= ~0x0000000F;
|
||||
LPC_PINCON->PINSEL0 |= 0x0000000A; /* RxD3 is P0.1 and TxD3 is P0.0 */
|
||||
LPC_SC->PCONP |= 1<<4 | 1<<25; //Enable PCUART1
|
||||
/* By default, the PCLKSELx value is zero, thus, the PCLK for
|
||||
all the peripherals is 1/4 of the SystemFrequency. */
|
||||
/* Bit 6~7 is for UART3 */
|
||||
pclkdiv = (LPC_SC->PCLKSEL1 >> 18) & 0x03;
|
||||
switch ( pclkdiv )
|
||||
{
|
||||
case 0x00:
|
||||
default:
|
||||
pclk = SystemCoreClock/4;
|
||||
break;
|
||||
case 0x01:
|
||||
pclk = SystemCoreClock;
|
||||
break;
|
||||
case 0x02:
|
||||
pclk = SystemCoreClock/2;
|
||||
break;
|
||||
case 0x03:
|
||||
pclk = SystemCoreClock/8;
|
||||
break;
|
||||
}
|
||||
LPC_UART3->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
|
||||
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */
|
||||
LPC_UART3->DLM = Fdiv / 256;
|
||||
LPC_UART3->DLL = Fdiv % 256;
|
||||
LPC_UART3->LCR = 0x03; /* DLAB = 0 */
|
||||
LPC_UART3->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
|
||||
|
||||
NVIC_EnableIRQ(UART3_IRQn);
|
||||
|
||||
LPC_UART3->IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART3 interrupt */
|
||||
}
|
||||
}
|
||||
|
||||
int HardwareSerial::read() {
|
||||
uint8_t rx;
|
||||
if ( PortNum == 0 )
|
||||
{
|
||||
if (UART0RxQueueReadPos == UART0RxQueueWritePos)
|
||||
return -1;
|
||||
|
||||
// Read from "head"
|
||||
rx = UART0Buffer[UART0RxQueueReadPos]; // grab next byte
|
||||
UART0RxQueueReadPos = (UART0RxQueueReadPos + 1) % UARTRXQUEUESIZE;
|
||||
return rx;
|
||||
}
|
||||
if ( PortNum == 1 )
|
||||
{
|
||||
if (UART1RxQueueReadPos == UART1RxQueueWritePos)
|
||||
return -1;
|
||||
|
||||
// Read from "head"
|
||||
rx = UART1Buffer[UART1RxQueueReadPos]; // grab next byte
|
||||
UART1RxQueueReadPos = (UART1RxQueueReadPos + 1) % UARTRXQUEUESIZE;
|
||||
return rx;
|
||||
}
|
||||
if ( PortNum == 2 )
|
||||
{
|
||||
if (UART2RxQueueReadPos == UART2RxQueueWritePos)
|
||||
return -1;
|
||||
|
||||
// Read from "head"
|
||||
rx = UART2Buffer[UART2RxQueueReadPos]; // grab next byte
|
||||
UART2RxQueueReadPos = (UART2RxQueueReadPos + 1) % UARTRXQUEUESIZE;
|
||||
return rx;
|
||||
}
|
||||
if ( PortNum == 3 )
|
||||
{
|
||||
if (UART3RxQueueReadPos == UART3RxQueueWritePos)
|
||||
return -1;
|
||||
|
||||
// Read from "head"
|
||||
rx = UART3Buffer[UART3RxQueueReadPos]; // grab next byte
|
||||
UART3RxQueueReadPos = (UART3RxQueueReadPos + 1) % UARTRXQUEUESIZE;
|
||||
return rx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t HardwareSerial::write(uint8_t send) {
|
||||
if ( PortNum == 0 )
|
||||
{
|
||||
/* THRE status, contain valid data */
|
||||
while ( !(UART0TxEmpty & 0x01) );
|
||||
LPC_UART0->THR = send;
|
||||
UART0TxEmpty = 0; /* not empty in the THR until it shifts out */
|
||||
}
|
||||
else if (PortNum == 1)
|
||||
{
|
||||
|
||||
/* THRE status, contain valid data */
|
||||
while ( !(UART1TxEmpty & 0x01) );
|
||||
LPC_UART1->THR = send;
|
||||
UART1TxEmpty = 0; /* not empty in the THR until it shifts out */
|
||||
|
||||
|
||||
}
|
||||
else if ( PortNum == 2 )
|
||||
{
|
||||
/* THRE status, contain valid data */
|
||||
while ( !(UART2TxEmpty & 0x01) );
|
||||
LPC_UART2->THR = send;
|
||||
UART2TxEmpty = 0; /* not empty in the THR until it shifts out */
|
||||
|
||||
}
|
||||
else if ( PortNum == 3 )
|
||||
{
|
||||
/* THRE status, contain valid data */
|
||||
while ( !(UART3TxEmpty & 0x01) );
|
||||
LPC_UART3->THR = send;
|
||||
UART3TxEmpty = 0; /* not empty in the THR until it shifts out */
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HardwareSerial::available() {
|
||||
if ( PortNum == 0 )
|
||||
{
|
||||
return (UART0RxQueueWritePos + UARTRXQUEUESIZE - UART0RxQueueReadPos) % UARTRXQUEUESIZE;
|
||||
}
|
||||
if ( PortNum == 1 )
|
||||
{
|
||||
return (UART1RxQueueWritePos + UARTRXQUEUESIZE - UART1RxQueueReadPos) % UARTRXQUEUESIZE;
|
||||
}
|
||||
if ( PortNum == 2 )
|
||||
{
|
||||
return (UART2RxQueueWritePos + UARTRXQUEUESIZE - UART2RxQueueReadPos) % UARTRXQUEUESIZE;
|
||||
}
|
||||
if ( PortNum == 3 )
|
||||
{
|
||||
return (UART3RxQueueWritePos + UARTRXQUEUESIZE - UART3RxQueueReadPos) % UARTRXQUEUESIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HardwareSerial::flush() {
|
||||
if ( PortNum == 0 )
|
||||
{
|
||||
UART0RxQueueWritePos = 0;
|
||||
UART0RxQueueReadPos = 0;
|
||||
|
||||
}
|
||||
if ( PortNum == 1 )
|
||||
{
|
||||
UART1RxQueueWritePos = 0;
|
||||
UART1RxQueueReadPos = 0;
|
||||
}
|
||||
if ( PortNum == 2 )
|
||||
{
|
||||
UART2RxQueueWritePos = 0;
|
||||
UART2RxQueueReadPos = 0;
|
||||
}
|
||||
if ( PortNum == 3 )
|
||||
{
|
||||
UART3RxQueueWritePos = 0;
|
||||
UART3RxQueueReadPos = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void HardwareSerial::printf(const char *format, ...) {
|
||||
static char buffer[256];
|
||||
va_list vArgs;
|
||||
va_start(vArgs, format);
|
||||
int length = vsnprintf((char *) buffer, 256, (char const *) format, vArgs);
|
||||
va_end(vArgs);
|
||||
if (length > 0 && length < 256) {
|
||||
for (int i = 0; i < length;) {
|
||||
write(buffer[i]);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
** Function name: UART0_IRQHandler
|
||||
**
|
||||
** Descriptions: UART0 interrupt handler
|
||||
**
|
||||
** parameters: None
|
||||
** Returned value: None
|
||||
**
|
||||
*****************************************************************************/
|
||||
void UART0_IRQHandler (void)
|
||||
{
|
||||
uint8_t IIRValue, LSRValue;
|
||||
uint8_t Dummy = Dummy;
|
||||
|
||||
IIRValue = LPC_UART0->IIR;
|
||||
|
||||
IIRValue >>= 1; /* skip pending bit in IIR */
|
||||
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
|
||||
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
|
||||
{
|
||||
LSRValue = LPC_UART0->LSR;
|
||||
/* Receive Line Status */
|
||||
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
|
||||
{
|
||||
/* There are errors or break interrupt */
|
||||
/* Read LSR will clear the interrupt */
|
||||
UART0Status = LSRValue;
|
||||
Dummy = LPC_UART0->RBR; /* Dummy read on RX to clear
|
||||
interrupt, then bail out */
|
||||
return;
|
||||
}
|
||||
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
|
||||
{
|
||||
/* If no error on RLS, normal ready, save into the data buffer. */
|
||||
/* Note: read RBR will clear the interrupt */
|
||||
if ((UART0RxQueueWritePos+1) % UARTRXQUEUESIZE != UART0RxQueueReadPos)
|
||||
{
|
||||
UART0Buffer[UART0RxQueueWritePos] = LPC_UART0->RBR;
|
||||
UART0RxQueueWritePos = (UART0RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
else
|
||||
dummy = LPC_UART0->RBR;;
|
||||
}
|
||||
}
|
||||
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
|
||||
{
|
||||
/* Receive Data Available */
|
||||
if ((UART0RxQueueWritePos+1) % UARTRXQUEUESIZE != UART0RxQueueReadPos)
|
||||
{
|
||||
UART0Buffer[UART0RxQueueWritePos] = LPC_UART0->RBR;
|
||||
UART0RxQueueWritePos = (UART0RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
else
|
||||
dummy = LPC_UART1->RBR;;
|
||||
}
|
||||
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
|
||||
{
|
||||
/* Character Time-out indicator */
|
||||
UART0Status |= 0x100; /* Bit 9 as the CTI error */
|
||||
}
|
||||
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
|
||||
{
|
||||
/* THRE interrupt */
|
||||
LSRValue = LPC_UART0->LSR; /* Check status in the LSR to see if
|
||||
valid data in U0THR or not */
|
||||
if ( LSRValue & LSR_THRE )
|
||||
{
|
||||
UART0TxEmpty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UART0TxEmpty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
** Function name: UART1_IRQHandler
|
||||
**
|
||||
** Descriptions: UART1 interrupt handler
|
||||
**
|
||||
** parameters: None
|
||||
** Returned value: None
|
||||
**
|
||||
*****************************************************************************/
|
||||
void UART1_IRQHandler (void)
|
||||
{
|
||||
uint8_t IIRValue, LSRValue;
|
||||
uint8_t Dummy = Dummy;
|
||||
|
||||
IIRValue = LPC_UART1->IIR;
|
||||
|
||||
IIRValue >>= 1; /* skip pending bit in IIR */
|
||||
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
|
||||
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
|
||||
{
|
||||
LSRValue = LPC_UART1->LSR;
|
||||
/* Receive Line Status */
|
||||
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
|
||||
{
|
||||
/* There are errors or break interrupt */
|
||||
/* Read LSR will clear the interrupt */
|
||||
UART1Status = LSRValue;
|
||||
Dummy = LPC_UART1->RBR; /* Dummy read on RX to clear
|
||||
interrupt, then bail out */
|
||||
return;
|
||||
}
|
||||
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
|
||||
{
|
||||
/* If no error on RLS, normal ready, save into the data buffer. */
|
||||
/* Note: read RBR will clear the interrupt */
|
||||
if ((UART1RxQueueWritePos+1) % UARTRXQUEUESIZE != UART1RxQueueReadPos)
|
||||
{
|
||||
UART1Buffer[UART1RxQueueWritePos] = LPC_UART1->RBR;
|
||||
UART1RxQueueWritePos =(UART1RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
else
|
||||
dummy = LPC_UART1->RBR;;
|
||||
}
|
||||
}
|
||||
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
|
||||
{
|
||||
/* Receive Data Available */
|
||||
if ((UART1RxQueueWritePos+1) % UARTRXQUEUESIZE != UART1RxQueueReadPos)
|
||||
{
|
||||
UART1Buffer[UART1RxQueueWritePos] = LPC_UART1->RBR;
|
||||
UART1RxQueueWritePos = (UART1RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
else
|
||||
dummy = LPC_UART1->RBR;;
|
||||
}
|
||||
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
|
||||
{
|
||||
/* Character Time-out indicator */
|
||||
UART1Status |= 0x100; /* Bit 9 as the CTI error */
|
||||
}
|
||||
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
|
||||
{
|
||||
/* THRE interrupt */
|
||||
LSRValue = LPC_UART1->LSR; /* Check status in the LSR to see if
|
||||
valid data in U0THR or not */
|
||||
if ( LSRValue & LSR_THRE )
|
||||
{
|
||||
UART1TxEmpty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UART1TxEmpty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*****************************************************************************
|
||||
** Function name: UART2_IRQHandler
|
||||
**
|
||||
** Descriptions: UART2 interrupt handler
|
||||
**
|
||||
** parameters: None
|
||||
** Returned value: None
|
||||
**
|
||||
*****************************************************************************/
|
||||
void UART2_IRQHandler (void)
|
||||
{
|
||||
uint8_t IIRValue, LSRValue;
|
||||
uint8_t Dummy = Dummy;
|
||||
|
||||
IIRValue = LPC_UART2->IIR;
|
||||
|
||||
IIRValue >>= 1; /* skip pending bit in IIR */
|
||||
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
|
||||
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
|
||||
{
|
||||
LSRValue = LPC_UART2->LSR;
|
||||
/* Receive Line Status */
|
||||
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
|
||||
{
|
||||
/* There are errors or break interrupt */
|
||||
/* Read LSR will clear the interrupt */
|
||||
UART2Status = LSRValue;
|
||||
Dummy = LPC_UART2->RBR; /* Dummy read on RX to clear
|
||||
interrupt, then bail out */
|
||||
return;
|
||||
}
|
||||
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
|
||||
{
|
||||
/* If no error on RLS, normal ready, save into the data buffer. */
|
||||
/* Note: read RBR will clear the interrupt */
|
||||
if ((UART2RxQueueWritePos+1) % UARTRXQUEUESIZE != UART2RxQueueReadPos)
|
||||
{
|
||||
UART2Buffer[UART2RxQueueWritePos] = LPC_UART2->RBR;
|
||||
UART2RxQueueWritePos = (UART2RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
|
||||
{
|
||||
/* Receive Data Available */
|
||||
if ((UART2RxQueueWritePos+1) % UARTRXQUEUESIZE != UART2RxQueueReadPos)
|
||||
{
|
||||
UART2Buffer[UART2RxQueueWritePos] = LPC_UART2->RBR;
|
||||
UART2RxQueueWritePos = (UART2RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
else
|
||||
dummy = LPC_UART2->RBR;;
|
||||
}
|
||||
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
|
||||
{
|
||||
/* Character Time-out indicator */
|
||||
UART2Status |= 0x100; /* Bit 9 as the CTI error */
|
||||
}
|
||||
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
|
||||
{
|
||||
/* THRE interrupt */
|
||||
LSRValue = LPC_UART2->LSR; /* Check status in the LSR to see if
|
||||
valid data in U0THR or not */
|
||||
if ( LSRValue & LSR_THRE )
|
||||
{
|
||||
UART2TxEmpty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UART2TxEmpty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
** Function name: UART3_IRQHandler
|
||||
**
|
||||
** Descriptions: UART0 interrupt handler
|
||||
**
|
||||
** parameters: None
|
||||
** Returned value: None
|
||||
**
|
||||
*****************************************************************************/
|
||||
void UART3_IRQHandler (void)
|
||||
{
|
||||
uint8_t IIRValue, LSRValue;
|
||||
uint8_t Dummy = Dummy;
|
||||
|
||||
IIRValue = LPC_UART3->IIR;
|
||||
|
||||
IIRValue >>= 1; /* skip pending bit in IIR */
|
||||
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
|
||||
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
|
||||
{
|
||||
LSRValue = LPC_UART3->LSR;
|
||||
/* Receive Line Status */
|
||||
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
|
||||
{
|
||||
/* There are errors or break interrupt */
|
||||
/* Read LSR will clear the interrupt */
|
||||
UART3Status = LSRValue;
|
||||
Dummy = LPC_UART3->RBR; /* Dummy read on RX to clear
|
||||
interrupt, then bail out */
|
||||
return;
|
||||
}
|
||||
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
|
||||
{
|
||||
/* If no error on RLS, normal ready, save into the data buffer. */
|
||||
/* Note: read RBR will clear the interrupt */
|
||||
if ((UART3RxQueueWritePos+1) % UARTRXQUEUESIZE != UART3RxQueueReadPos)
|
||||
{
|
||||
UART3Buffer[UART3RxQueueWritePos] = LPC_UART3->RBR;
|
||||
UART3RxQueueWritePos = (UART3RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
|
||||
{
|
||||
/* Receive Data Available */
|
||||
if ((UART3RxQueueWritePos+1) % UARTRXQUEUESIZE != UART3RxQueueReadPos)
|
||||
{
|
||||
UART3Buffer[UART3RxQueueWritePos] = LPC_UART3->RBR;
|
||||
UART3RxQueueWritePos = (UART3RxQueueWritePos+1) % UARTRXQUEUESIZE;
|
||||
}
|
||||
else
|
||||
dummy = LPC_UART3->RBR;;
|
||||
}
|
||||
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
|
||||
{
|
||||
/* Character Time-out indicator */
|
||||
UART3Status |= 0x100; /* Bit 9 as the CTI error */
|
||||
}
|
||||
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
|
||||
{
|
||||
/* THRE interrupt */
|
||||
LSRValue = LPC_UART3->LSR; /* Check status in the LSR to see if
|
||||
valid data in U0THR or not */
|
||||
if ( LSRValue & LSR_THRE )
|
||||
{
|
||||
UART3TxEmpty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UART3TxEmpty = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program 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 program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HARDWARE_SERIAL_H_
|
||||
#define HARDWARE_SERIAL_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <Stream.h>
|
||||
|
||||
extern "C" {
|
||||
#include <debug_frmwrk.h>
|
||||
|
||||
//#include <lpc17xx_uart.h>
|
||||
}
|
||||
|
||||
#define IER_RBR 0x01
|
||||
#define IER_THRE 0x02
|
||||
#define IER_RLS 0x04
|
||||
|
||||
#define IIR_PEND 0x01
|
||||
#define IIR_RLS 0x03
|
||||
#define IIR_RDA 0x02
|
||||
#define IIR_CTI 0x06
|
||||
#define IIR_THRE 0x01
|
||||
|
||||
#define LSR_RDR 0x01
|
||||
#define LSR_OE 0x02
|
||||
#define LSR_PE 0x04
|
||||
#define LSR_FE 0x08
|
||||
#define LSR_BI 0x10
|
||||
#define LSR_THRE 0x20
|
||||
#define LSR_TEMT 0x40
|
||||
#define LSR_RXFE 0x80
|
||||
|
||||
#define UARTRXQUEUESIZE 0x10
|
||||
|
||||
class HardwareSerial : public Stream {
|
||||
private:
|
||||
uint8_t PortNum;
|
||||
uint32_t baudrate;
|
||||
|
||||
public:
|
||||
HardwareSerial(uint32_t uart) :
|
||||
PortNum(uart)
|
||||
{
|
||||
}
|
||||
|
||||
void begin(uint32_t baudrate);
|
||||
int read();
|
||||
size_t write(uint8_t send);
|
||||
int available();
|
||||
void flush();
|
||||
void printf(const char *format, ...);
|
||||
int peek() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
operator bool() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void print(const char value[]) {
|
||||
printf("%s" , value);
|
||||
}
|
||||
void print(char value, int = 0) {
|
||||
printf("%c" , value);
|
||||
}
|
||||
void print(unsigned char value, int = 0) {
|
||||
printf("%u" , value);
|
||||
}
|
||||
void print(int value, int = 0) {
|
||||
printf("%d" , value);
|
||||
}
|
||||
void print(unsigned int value, int = 0) {
|
||||
printf("%u" , value);
|
||||
}
|
||||
void print(long value, int = 0) {
|
||||
printf("%ld" , value);
|
||||
}
|
||||
void print(unsigned long value, int = 0) {
|
||||
printf("%lu" , value);
|
||||
}
|
||||
|
||||
void print(float value, int round = 6) {
|
||||
printf("%f" , value);
|
||||
}
|
||||
void print(double value, int round = 6) {
|
||||
printf("%f" , value );
|
||||
}
|
||||
|
||||
void println(const char value[]) {
|
||||
printf("%s\n" , value);
|
||||
}
|
||||
void println(char value, int = 0) {
|
||||
printf("%c\n" , value);
|
||||
}
|
||||
void println(unsigned char value, int = 0) {
|
||||
printf("%u\r\n" , value);
|
||||
}
|
||||
void println(int value, int = 0) {
|
||||
printf("%d\n" , value);
|
||||
}
|
||||
void println(unsigned int value, int = 0) {
|
||||
printf("%u\n" , value);
|
||||
}
|
||||
void println(long value, int = 0) {
|
||||
printf("%ld\n" , value);
|
||||
}
|
||||
void println(unsigned long value, int = 0) {
|
||||
printf("%lu\n" , value);
|
||||
}
|
||||
void println(float value, int round = 6) {
|
||||
printf("%f\n" , value );
|
||||
}
|
||||
void println(double value, int round = 6) {
|
||||
printf("%f\n" , value );
|
||||
}
|
||||
void println(void) {
|
||||
print('\n');
|
||||
}
|
||||
|
||||
};
|
||||
//extern HardwareSerial Serial0;
|
||||
//extern HardwareSerial Serial1;
|
||||
//extern HardwareSerial Serial2;
|
||||
extern HardwareSerial Serial3;
|
||||
|
||||
#endif /* MARLIN_SRC_HAL_HAL_SERIAL_H_ */
|
@ -0,0 +1,398 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// Includes
|
||||
//
|
||||
//#include <WInterrupts.h>
|
||||
#include "../../../macros.h"
|
||||
#include "../HAL.h"
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include "arduino.h"
|
||||
#include "pinmapping.h"
|
||||
#include "pinmap_re_arm.h"
|
||||
#include "fastio.h"
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
void GpioEnableInt(uint32_t port, uint32_t pin, uint32_t mode);
|
||||
void GpioDisableInt(uint32_t port, uint32_t pin);
|
||||
//
|
||||
// Statics
|
||||
//
|
||||
SoftwareSerial *SoftwareSerial::active_object = 0;
|
||||
unsigned char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
|
||||
volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
|
||||
volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;
|
||||
|
||||
typedef struct _DELAY_TABLE
|
||||
{
|
||||
long baud;
|
||||
uint16_t rx_delay_centering;
|
||||
uint16_t rx_delay_intrabit;
|
||||
uint16_t rx_delay_stopbit;
|
||||
uint16_t tx_delay;
|
||||
} DELAY_TABLE;
|
||||
|
||||
// rough delay estimation
|
||||
static const DELAY_TABLE table[] =
|
||||
{
|
||||
//baud |rxcenter|rxintra |rxstop |tx
|
||||
{ 250000, 2, 4, 4, 4, }, //Done but not good due to instruction cycle error
|
||||
{ 115200, 4, 8, 8, 8, }, //Done but not good due to instruction cycle error
|
||||
//{ 74880, 69, 139, 62, 162, }, // estimation
|
||||
// { 57600, 100, 185, 1, 208, }, // Done but not good due to instruction cycle error
|
||||
//{ 38400, 13, 26, 26, 26, }, // Done
|
||||
//{ 19200, 26, 52, 52, 52, }, // Done
|
||||
{ 9600, 52, 104, 104, 104, }, // Done
|
||||
//{ 4800, 104, 208, 208, 208, },
|
||||
//{ 2400, 208, 417, 417, 417, },
|
||||
//{ 1200, 416, 833, 833, 833,},
|
||||
};
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
|
||||
#if 0
|
||||
/* static */
|
||||
inline void SoftwareSerial::tunedDelay(uint32_t count) {
|
||||
|
||||
asm volatile(
|
||||
|
||||
"mov r3, %[loopsPerMicrosecond] \n\t" //load the initial loop counter
|
||||
"1: \n\t"
|
||||
"sub r3, r3, #1 \n\t"
|
||||
"bne 1b \n\t"
|
||||
|
||||
://empty output list
|
||||
:[loopsPerMicrosecond] "r" (count)
|
||||
:"r3", "cc" //clobber list
|
||||
);
|
||||
|
||||
}
|
||||
#else
|
||||
inline void SoftwareSerial::tunedDelay(uint32_t count) {
|
||||
delayMicroseconds(count);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function sets the current object as the "listening"
|
||||
// one and returns true if it replaces another
|
||||
bool SoftwareSerial::listen()
|
||||
{
|
||||
if (!_rx_delay_stopbit)
|
||||
return false;
|
||||
|
||||
if (active_object != this)
|
||||
{
|
||||
if (active_object)
|
||||
active_object->stopListening();
|
||||
|
||||
_buffer_overflow = false;
|
||||
_receive_buffer_head = _receive_buffer_tail = 0;
|
||||
active_object = this;
|
||||
|
||||
setRxIntMsk(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stop listening. Returns true if we were actually listening.
|
||||
bool SoftwareSerial::stopListening()
|
||||
{
|
||||
if (active_object == this)
|
||||
{
|
||||
setRxIntMsk(false);
|
||||
active_object = NULL;
|
||||
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 ? rx_pin_read() : !rx_pin_read())
|
||||
{
|
||||
// Disable further interrupts during reception, this prevents
|
||||
// triggering another interrupt directly after we return, which can
|
||||
// cause problems at higher baudrates.
|
||||
setRxIntMsk(false);//__disable_irq();//
|
||||
|
||||
// Wait approximately 1/2 of a bit width to "center" the sample
|
||||
tunedDelay(_rx_delay_centering);
|
||||
// Read each of the 8 bits
|
||||
for (uint8_t i=8; i > 0; --i)
|
||||
{
|
||||
tunedDelay(_rx_delay_intrabit);
|
||||
d >>= 1;
|
||||
if (rx_pin_read())
|
||||
d |= 0x80;
|
||||
}
|
||||
|
||||
if (_inverse_logic)
|
||||
d = ~d;
|
||||
|
||||
// if buffer full, set the overflow flag and return
|
||||
uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
|
||||
if (next != _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 = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer_overflow = true;
|
||||
}
|
||||
tunedDelay(_rx_delay_stopbit);
|
||||
// Re-enable interrupts when we're sure to be inside the stop bit
|
||||
setRxIntMsk(true);//__enable_irq();//
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SoftwareSerial::rx_pin_read()
|
||||
{
|
||||
return digitalRead(_receivePin);
|
||||
}
|
||||
|
||||
//
|
||||
// Interrupt handling
|
||||
//
|
||||
|
||||
/* static */
|
||||
inline void SoftwareSerial::handle_interrupt()
|
||||
{
|
||||
if (active_object)
|
||||
{
|
||||
active_object->recv();
|
||||
}
|
||||
}
|
||||
extern "C" void intWrapper() {
|
||||
SoftwareSerial::handle_interrupt();
|
||||
}
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
// First write, then set output. If we do this the other way around,
|
||||
// the pin would be output low for a short while before switching to
|
||||
// output hihg. Now, it is input with pullup for a short while, which
|
||||
// is fine. With inverse logic, either order is fine.
|
||||
|
||||
digitalWrite(tx, _inverse_logic ? LOW : HIGH);
|
||||
pinMode(tx,OUTPUT);
|
||||
_transmitPin = tx;
|
||||
|
||||
}
|
||||
|
||||
void SoftwareSerial::setRX(uint8_t rx)
|
||||
{
|
||||
pinMode(rx, INPUT_PULLUP); // pullup for normal logic!
|
||||
//if (!_inverse_logic)
|
||||
// digitalWrite(rx, HIGH);
|
||||
_receivePin = rx;
|
||||
_receivePort = pin_map[rx].port;
|
||||
_receivePortPin = pin_map[rx].pin;
|
||||
/* GPIO_T * rxPort = digitalPinToPort(rx);
|
||||
_receivePortRegister = portInputRegister(rxPort);
|
||||
_receiveBitMask = digitalPinToBitMask(rx);*/
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
|
||||
void SoftwareSerial::begin(long speed)
|
||||
{
|
||||
_rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;
|
||||
|
||||
for(uint8_t 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;
|
||||
}
|
||||
}
|
||||
|
||||
attachInterrupt(_receivePin, intWrapper, CHANGE); //this->handle_interrupt, CHANGE);
|
||||
|
||||
listen();
|
||||
tunedDelay(_tx_delay);
|
||||
|
||||
}
|
||||
|
||||
void SoftwareSerial::setRxIntMsk(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
GpioEnableInt(_receivePort,_receivePin,CHANGE);
|
||||
else
|
||||
GpioDisableInt(_receivePort,_receivePin);
|
||||
}
|
||||
|
||||
void SoftwareSerial::end()
|
||||
{
|
||||
stopListening();
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::write(uint8_t b)
|
||||
{
|
||||
// By declaring these as local variables, the compiler will put them
|
||||
// in registers _before_ disabling interrupts and entering the
|
||||
// critical timing sections below, which makes it a lot easier to
|
||||
// verify the cycle timings
|
||||
|
||||
bool inv = _inverse_logic;
|
||||
uint16_t delay = _tx_delay;
|
||||
|
||||
if(inv)
|
||||
b = ~b;
|
||||
|
||||
cli(); // turn off interrupts for a clean txmit
|
||||
|
||||
// Write the start bit
|
||||
if (inv)
|
||||
digitalWrite(_transmitPin, 1);
|
||||
else
|
||||
digitalWrite(_transmitPin, 0);
|
||||
|
||||
tunedDelay(delay);
|
||||
|
||||
// Write each of the 8 bits
|
||||
for (uint8_t i = 8; i > 0; --i)
|
||||
{
|
||||
if (b & 1) // choose bit
|
||||
digitalWrite(_transmitPin, 1); // send 1 //(GPIO_Desc[_transmitPin].P)->DOUT |= GPIO_Desc[_transmitPin].bit;
|
||||
else
|
||||
digitalWrite(_transmitPin, 0); // send 0 //(GPIO_Desc[_transmitPin].P)->DOUT &= ~GPIO_Desc[_transmitPin].bit;
|
||||
|
||||
tunedDelay(delay);
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
// restore pin to natural state
|
||||
if (inv)
|
||||
digitalWrite(_transmitPin, 0);
|
||||
else
|
||||
digitalWrite(_transmitPin, 1);
|
||||
|
||||
sei(); // turn interrupts back on
|
||||
tunedDelay(delay);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SoftwareSerial::flush()
|
||||
{
|
||||
if (!isListening())
|
||||
return;
|
||||
|
||||
cli();
|
||||
_receive_buffer_head = _receive_buffer_tail = 0;
|
||||
sei();
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
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 "arduino.h"
|
||||
#include <inttypes.h>
|
||||
//#include "serial.h"
|
||||
#include <Stream.h>
|
||||
#include <Print.h>
|
||||
|
||||
/******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
#define _SS_MAX_RX_BUFF 64 // RX buffer size
|
||||
|
||||
class SoftwareSerial : public Stream
|
||||
{
|
||||
private:
|
||||
// per object data
|
||||
uint8_t _receivePin;
|
||||
uint8_t _transmitPin;
|
||||
// uint32_t _receiveBitMask; // for rx interrupts
|
||||
uint32_t _receivePort;
|
||||
uint32_t _receivePortPin;
|
||||
|
||||
|
||||
// Expressed as 4-cycle delays (must never be 0!)
|
||||
uint16_t _rx_delay_centering;
|
||||
uint16_t _rx_delay_intrabit;
|
||||
uint16_t _rx_delay_stopbit;
|
||||
uint16_t _tx_delay;
|
||||
|
||||
uint16_t _buffer_overflow:1;
|
||||
uint16_t _inverse_logic:1;
|
||||
|
||||
// static data
|
||||
static unsigned 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() __attribute__((__always_inline__));
|
||||
uint32_t rx_pin_read();
|
||||
void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__));
|
||||
void setTX(uint8_t transmitPin);
|
||||
void setRX(uint8_t receivePin);
|
||||
void setRxIntMsk(bool enable) __attribute__((__always_inline__));
|
||||
|
||||
// private static method for timing
|
||||
static inline void tunedDelay(uint32_t delay);
|
||||
|
||||
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 stopListening();
|
||||
bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; }
|
||||
int peek();
|
||||
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual int read();
|
||||
virtual int available();
|
||||
virtual void flush();
|
||||
operator bool() { return true; }
|
||||
|
||||
using Print::write;
|
||||
//using HalSerial::write;
|
||||
|
||||
// public only for easy access by interrupt handlers
|
||||
static inline void handle_interrupt() __attribute__((__always_inline__));
|
||||
};
|
||||
|
||||
// Arduino 0012 workaround
|
||||
#undef int
|
||||
#undef char
|
||||
#undef long
|
||||
#undef byte
|
||||
#undef float
|
||||
#undef abs
|
||||
#undef round
|
||||
|
||||
#endif
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
Copyright (c) 2011-2012 Arduino. All right reserved.
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include "../../../macros.h"
|
||||
#include "../HAL.h"
|
||||
#include "arduino.h"
|
||||
#include "pinmapping.h"
|
||||
//#include "HAL_timers.h"
|
||||
#include "fastio.h"
|
||||
|
||||
#define GNUM 31
|
||||
|
||||
typedef void (*interruptCB)(void);
|
||||
|
||||
static interruptCB callbacksP0[GNUM];
|
||||
static interruptCB callbacksP2[GNUM];
|
||||
|
||||
extern "C" void GpioEnableInt(uint32_t port, uint32_t pin, uint32_t mode);
|
||||
extern "C" void GpioDisableInt(uint32_t port, uint32_t pin);
|
||||
|
||||
//void deadloop(void) {}
|
||||
|
||||
/* Configure PIO interrupt sources */
|
||||
static void __initialize() {
|
||||
int i;
|
||||
for (i=0; i<GNUM; i++) {
|
||||
callbacksP0[i] = 0;
|
||||
callbacksP2[i] = 0;
|
||||
}
|
||||
NVIC_EnableIRQ(EINT3_IRQn);
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t pin, void (*callback)(void), uint32_t mode)
|
||||
{
|
||||
static int enabled = 0;
|
||||
|
||||
if(!INTERRUPT_PIN(pin)) return;
|
||||
|
||||
if (!enabled) {
|
||||
__initialize();
|
||||
enabled = 1;
|
||||
}
|
||||
uint8_t myport = pin_map[pin].port;
|
||||
uint8_t mypin = pin_map[pin].pin;
|
||||
|
||||
|
||||
if (myport == 0 )
|
||||
callbacksP0[mypin] = callback;
|
||||
else
|
||||
callbacksP2[mypin] = callback;
|
||||
|
||||
// Enable interrupt
|
||||
GpioEnableInt(myport,mypin,mode);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t pin)
|
||||
{
|
||||
if(!INTERRUPT_PIN(pin)) return;
|
||||
|
||||
uint8_t myport = pin_map[pin].port;
|
||||
uint8_t mypin = pin_map[pin].pin;
|
||||
|
||||
// Disable interrupt
|
||||
GpioDisableInt(myport,mypin);
|
||||
|
||||
//unset callback
|
||||
if (myport == 0 )
|
||||
callbacksP0[mypin] = 0;
|
||||
else //if (myport == 2 )
|
||||
callbacksP2[mypin] = 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void GpioEnableInt(uint32_t port, uint32_t pin, uint32_t mode) {
|
||||
//pin here is the processor pin, not logical pin
|
||||
if (port==0) {
|
||||
LPC_GPIOINT->IO0IntClr = (1 << pin);
|
||||
if (mode ==RISING) {
|
||||
LPC_GPIOINT->IO0IntEnR |= (1<<pin);
|
||||
LPC_GPIOINT->IO0IntEnF &= ~(1<<pin);
|
||||
}
|
||||
else if (mode==FALLING) {
|
||||
LPC_GPIOINT->IO0IntEnF |= (1<<pin);
|
||||
LPC_GPIOINT->IO0IntEnR &= ~(1<<pin);
|
||||
}
|
||||
else if (mode==CHANGE) {
|
||||
LPC_GPIOINT->IO0IntEnR |= (1<<pin);
|
||||
LPC_GPIOINT->IO0IntEnF |= (1<<pin);
|
||||
}
|
||||
}
|
||||
else{
|
||||
LPC_GPIOINT->IO2IntClr = (1 << pin);
|
||||
if (mode ==RISING) {
|
||||
LPC_GPIOINT->IO2IntEnR |= (1<<pin);
|
||||
LPC_GPIOINT->IO2IntEnF &= ~(1<<pin);
|
||||
}
|
||||
else if (mode==FALLING) {
|
||||
LPC_GPIOINT->IO2IntEnF |= (1<<pin);
|
||||
LPC_GPIOINT->IO2IntEnR &= ~(1<<pin);
|
||||
}
|
||||
else if (mode==CHANGE) {
|
||||
LPC_GPIOINT->IO2IntEnR |= (1<<pin);
|
||||
LPC_GPIOINT->IO2IntEnF |= (1<<pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
extern "C" void GpioDisableInt(uint32_t port, uint32_t pin)
|
||||
{
|
||||
if (port==0){
|
||||
LPC_GPIOINT->IO0IntEnR &= ~(1<<pin);
|
||||
LPC_GPIOINT->IO0IntEnF &= ~(1<<pin);
|
||||
LPC_GPIOINT->IO0IntClr = 1 << pin;
|
||||
}
|
||||
else {
|
||||
LPC_GPIOINT->IO2IntEnR &= ~(1<<pin);
|
||||
LPC_GPIOINT->IO2IntEnF &= ~(1<<pin);
|
||||
LPC_GPIOINT->IO2IntClr = 1 << pin;
|
||||
}
|
||||
}
|
||||
|
||||
bool isPowerOf2(unsigned int n)
|
||||
|
||||
{
|
||||
|
||||
return n == 1 || (n & (n-1)) == 0;
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
extern "C" void EINT3_IRQHandler () {
|
||||
LPC_GPIOINT->IO0IntClr = LPC_GPIOINT->IO2IntClr = 0xFFFFFFFF;
|
||||
TOGGLE(13);
|
||||
//NVIC_ClearPendingIRQ(EINT3_IRQn);
|
||||
}
|
||||
#else
|
||||
extern "C" void EINT3_IRQHandler(void)
|
||||
{
|
||||
// Read in all current interrupt registers. We do this once as the
|
||||
// GPIO interrupt registers are on the APB bus, and this is slow.
|
||||
uint32_t rise0 = LPC_GPIOINT->IO0IntStatR;
|
||||
uint32_t fall0 = LPC_GPIOINT->IO0IntStatF;
|
||||
uint32_t rise2 = LPC_GPIOINT->IO2IntStatR;
|
||||
uint32_t fall2 = LPC_GPIOINT->IO2IntStatF;
|
||||
//Clear teh interrupts ASAP
|
||||
LPC_GPIOINT->IO0IntClr = LPC_GPIOINT->IO2IntClr = 0xFFFFFFFF;
|
||||
NVIC_ClearPendingIRQ(EINT3_IRQn);
|
||||
uint8_t bitloc;
|
||||
if (rise0 == 0)
|
||||
goto fall0;
|
||||
/* multiple pins changes happened.*/
|
||||
while(rise0 > 0) { //Continue as long as there are interrupts pending
|
||||
bitloc = 31 - __CLZ(rise0); //CLZ returns number of leading zeros, 31 minus that is location of first pending interrupt
|
||||
if (callbacksP0[bitloc]!=0)
|
||||
callbacksP0[bitloc]();
|
||||
rise0 -= 1<<bitloc;
|
||||
}
|
||||
fall0:
|
||||
if (fall0==0)
|
||||
goto rise2;
|
||||
/* if (isPowerOf2(fall0) && callbacksP0[31 - __CLZ(rise0)])
|
||||
callbacksP0[31 - __CLZ(rise0)](); */
|
||||
//LPC_GPIOINT->IO0IntClr = fall0;*/
|
||||
else {
|
||||
while(fall0 > 0) {
|
||||
bitloc = 31 - __CLZ(fall0);
|
||||
if (callbacksP0[bitloc]!=0)
|
||||
callbacksP0[bitloc]();
|
||||
fall0 -= 1<<bitloc;
|
||||
}
|
||||
}
|
||||
rise2:
|
||||
if (rise2==0)
|
||||
goto fall2;
|
||||
/*if ((rise2 & (rise2 - 1)) == 0) {
|
||||
callbacksP2[rise2]();
|
||||
//LPC_GPIOINT->IO2IntClr = rise2;
|
||||
}*/
|
||||
else {
|
||||
while(rise2 > 0) {
|
||||
bitloc = 31 - __CLZ(rise2);
|
||||
if (callbacksP2[bitloc]!=0)
|
||||
callbacksP2[bitloc]();
|
||||
//LPC_GPIOINT->IO2IntClr = 1 << bitloc;
|
||||
rise2 -= 1<<bitloc;
|
||||
}
|
||||
}
|
||||
fall2:
|
||||
if (fall2==0)
|
||||
goto end;
|
||||
/*if ((fall2 & (fall2 - 1)) == 0) {
|
||||
callbacksP2[fall2]();
|
||||
//LPC_GPIOINT->IO2IntClr = fall2;
|
||||
}*/
|
||||
else {
|
||||
while(fall2 > 0) {
|
||||
bitloc = 31 - __CLZ(fall2);
|
||||
if (callbacksP2[bitloc]!=0)
|
||||
callbacksP2[bitloc]();
|
||||
//LPC_GPIOINT->IO2IntClr = 1 << bitloc;
|
||||
fall2 -= 1<<bitloc;
|
||||
}
|
||||
end:
|
||||
//NVIC_ClearPendingIRQ(EINT3_IRQn);
|
||||
//LPC_GPIOINT->IO0IntClr = LPC_GPIOINT->IO2IntClr = 0xFFFFFFFF;
|
||||
//NVIC_ClearPendingIRQ(EINT3_IRQn);
|
||||
return; //silences warning
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue