Browse Source
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.pull/1/head
kfazz
7 years ago
committed by
Scott Lahteine
11 changed files with 2246 additions and 1 deletions
@ -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