cleanup code
This commit is contained in:
parent
6b40e88ecb
commit
de928cd14e
13 changed files with 1 additions and 2347 deletions
|
@ -16,7 +16,7 @@ CONTIKI_WITH_IPV6 = 1
|
||||||
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
|
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
|
||||||
LFLAGS += -lm
|
LFLAGS += -lm
|
||||||
|
|
||||||
PROJECT_SOURCEFILES += ${SKETCH}.cpp Adafruit_HTU21DF.cpp Wire.cpp twi.c new.cpp WString.cpp Stream.cpp OneWire.cpp DallasTemperature.cpp
|
PROJECT_SOURCEFILES += ${SKETCH}.cpp Adafruit_HTU21DF.cpp OneWire.cpp DallasTemperature.cpp
|
||||||
|
|
||||||
# automatically build RESTful resources
|
# automatically build RESTful resources
|
||||||
REST_RESOURCES_DIR = ./resources
|
REST_RESOURCES_DIR = ./resources
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
Print.h - Base class that provides print() and println()
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef Print_h
|
|
||||||
#define Print_h
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h> // for size_t
|
|
||||||
|
|
||||||
#include "WString.h"
|
|
||||||
#include "Printable.h"
|
|
||||||
|
|
||||||
#define DEC 10
|
|
||||||
#define HEX 16
|
|
||||||
#define OCT 8
|
|
||||||
#define BIN 2
|
|
||||||
|
|
||||||
class Print
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int write_error;
|
|
||||||
size_t printNumber(unsigned long, uint8_t);
|
|
||||||
size_t printFloat(double, uint8_t);
|
|
||||||
protected:
|
|
||||||
void setWriteError(int err = 1) { write_error = err; }
|
|
||||||
public:
|
|
||||||
Print() : write_error(0) {}
|
|
||||||
|
|
||||||
int getWriteError() { return write_error; }
|
|
||||||
void clearWriteError() { setWriteError(0); }
|
|
||||||
|
|
||||||
virtual size_t write(uint8_t) = 0;
|
|
||||||
size_t write(const char *str) {
|
|
||||||
if (str == NULL) return 0;
|
|
||||||
return write((const uint8_t *)str, strlen(str));
|
|
||||||
}
|
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
|
||||||
|
|
||||||
size_t print(const __FlashStringHelper *);
|
|
||||||
size_t print(const String &);
|
|
||||||
size_t print(const char[]);
|
|
||||||
size_t print(char);
|
|
||||||
size_t print(unsigned char, int = DEC);
|
|
||||||
size_t print(int, int = DEC);
|
|
||||||
size_t print(unsigned int, int = DEC);
|
|
||||||
size_t print(long, int = DEC);
|
|
||||||
size_t print(unsigned long, int = DEC);
|
|
||||||
size_t print(double, int = 2);
|
|
||||||
size_t print(const Printable&);
|
|
||||||
|
|
||||||
size_t println(const __FlashStringHelper *);
|
|
||||||
size_t println(const String &s);
|
|
||||||
size_t println(const char[]);
|
|
||||||
size_t println(char);
|
|
||||||
size_t println(unsigned char, int = DEC);
|
|
||||||
size_t println(int, int = DEC);
|
|
||||||
size_t println(unsigned int, int = DEC);
|
|
||||||
size_t println(long, int = DEC);
|
|
||||||
size_t println(unsigned long, int = DEC);
|
|
||||||
size_t println(double, int = 2);
|
|
||||||
size_t println(const Printable&);
|
|
||||||
size_t println(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
Printable.h - Interface class that allows printing of complex types
|
|
||||||
Copyright (c) 2011 Adrian McEwen. 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef Printable_h
|
|
||||||
#define Printable_h
|
|
||||||
|
|
||||||
#include <new.h>
|
|
||||||
|
|
||||||
class Print;
|
|
||||||
|
|
||||||
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
|
||||||
By deriving from Printable and implementing the printTo method, it will then be possible
|
|
||||||
for users to print out instances of this class by passing them into the usual
|
|
||||||
Print::print and Print::println methods.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Printable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual size_t printTo(Print& p) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,270 +0,0 @@
|
||||||
/*
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "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, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
size_t index = 0; // maximum target string length is 64k bytes!
|
|
||||||
size_t termIndex = 0;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
if( *target == 0)
|
|
||||||
return true; // return true if target is a null string
|
|
||||||
while( (c = timedRead()) > 0){
|
|
||||||
|
|
||||||
if(c != target[index])
|
|
||||||
index = 0; // reset index if any char does not match
|
|
||||||
|
|
||||||
if( c == target[index]){
|
|
||||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
|
|
||||||
if(++index >= targetLen){ // return true if all chars in the target match
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(termLen > 0 && c == terminator[termIndex]){
|
|
||||||
if(++termIndex >= termLen)
|
|
||||||
return false; // return false if terminate string found before target string
|
|
||||||
}
|
|
||||||
else
|
|
||||||
termIndex = 0;
|
|
||||||
}
|
|
||||||
return 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)
|
|
||||||
{
|
|
||||||
boolean 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){
|
|
||||||
boolean isNegative = false;
|
|
||||||
boolean 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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
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 <inttypes.h>
|
|
||||||
#include "Print.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
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
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
|
|
||||||
// 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
|
|
||||||
// returns true if target string is found, false if timed out
|
|
||||||
|
|
||||||
bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
|
|
||||||
|
|
||||||
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
// 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
|
|
||||||
// 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
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,645 +0,0 @@
|
||||||
/*
|
|
||||||
WString.cpp - String library for Wiring & Arduino
|
|
||||||
...mostly rewritten by Paul Stoffregen...
|
|
||||||
Copyright (c) 2009-10 Hernando Barragan. All rights 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WString.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Constructors */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
String::String(const char *cstr)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
if (cstr) copy(cstr, strlen(cstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(const String &value)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
*this = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
|
||||||
String::String(String &&rval)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
move(rval);
|
|
||||||
}
|
|
||||||
String::String(StringSumHelper &&rval)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
move(rval);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String::String(char c)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
char buf[2];
|
|
||||||
buf[0] = c;
|
|
||||||
buf[1] = 0;
|
|
||||||
*this = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(unsigned char value, unsigned char base)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
char buf[9];
|
|
||||||
utoa(value, buf, base);
|
|
||||||
*this = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(int value, unsigned char base)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
char buf[18];
|
|
||||||
itoa(value, buf, base);
|
|
||||||
*this = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(unsigned int value, unsigned char base)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
char buf[17];
|
|
||||||
utoa(value, buf, base);
|
|
||||||
*this = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(long value, unsigned char base)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
char buf[34];
|
|
||||||
ltoa(value, buf, base);
|
|
||||||
*this = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::String(unsigned long value, unsigned char base)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
char buf[33];
|
|
||||||
ultoa(value, buf, base);
|
|
||||||
*this = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
String::~String()
|
|
||||||
{
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Memory Management */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
inline void String::init(void)
|
|
||||||
{
|
|
||||||
buffer = NULL;
|
|
||||||
capacity = 0;
|
|
||||||
len = 0;
|
|
||||||
flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::invalidate(void)
|
|
||||||
{
|
|
||||||
if (buffer) free(buffer);
|
|
||||||
buffer = NULL;
|
|
||||||
capacity = len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::reserve(unsigned int size)
|
|
||||||
{
|
|
||||||
if (buffer && capacity >= size) return 1;
|
|
||||||
if (changeBuffer(size)) {
|
|
||||||
if (len == 0) buffer[0] = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::changeBuffer(unsigned int maxStrLen)
|
|
||||||
{
|
|
||||||
char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
|
|
||||||
if (newbuffer) {
|
|
||||||
buffer = newbuffer;
|
|
||||||
capacity = maxStrLen;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Copy and Move */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
String & String::copy(const char *cstr, unsigned int length)
|
|
||||||
{
|
|
||||||
if (!reserve(length)) {
|
|
||||||
invalidate();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
len = length;
|
|
||||||
strcpy(buffer, cstr);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
|
||||||
void String::move(String &rhs)
|
|
||||||
{
|
|
||||||
if (buffer) {
|
|
||||||
if (capacity >= rhs.len) {
|
|
||||||
strcpy(buffer, rhs.buffer);
|
|
||||||
len = rhs.len;
|
|
||||||
rhs.len = 0;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer = rhs.buffer;
|
|
||||||
capacity = rhs.capacity;
|
|
||||||
len = rhs.len;
|
|
||||||
rhs.buffer = NULL;
|
|
||||||
rhs.capacity = 0;
|
|
||||||
rhs.len = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String & String::operator = (const String &rhs)
|
|
||||||
{
|
|
||||||
if (this == &rhs) return *this;
|
|
||||||
|
|
||||||
if (rhs.buffer) copy(rhs.buffer, rhs.len);
|
|
||||||
else invalidate();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
|
||||||
String & String::operator = (String &&rval)
|
|
||||||
{
|
|
||||||
if (this != &rval) move(rval);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String & String::operator = (StringSumHelper &&rval)
|
|
||||||
{
|
|
||||||
if (this != &rval) move(rval);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String & String::operator = (const char *cstr)
|
|
||||||
{
|
|
||||||
if (cstr) copy(cstr, strlen(cstr));
|
|
||||||
else invalidate();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* concat */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
unsigned char String::concat(const String &s)
|
|
||||||
{
|
|
||||||
return concat(s.buffer, s.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(const char *cstr, unsigned int length)
|
|
||||||
{
|
|
||||||
unsigned int newlen = len + length;
|
|
||||||
if (!cstr) return 0;
|
|
||||||
if (length == 0) return 1;
|
|
||||||
if (!reserve(newlen)) return 0;
|
|
||||||
strcpy(buffer + len, cstr);
|
|
||||||
len = newlen;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(const char *cstr)
|
|
||||||
{
|
|
||||||
if (!cstr) return 0;
|
|
||||||
return concat(cstr, strlen(cstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(char c)
|
|
||||||
{
|
|
||||||
char buf[2];
|
|
||||||
buf[0] = c;
|
|
||||||
buf[1] = 0;
|
|
||||||
return concat(buf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(unsigned char num)
|
|
||||||
{
|
|
||||||
char buf[4];
|
|
||||||
itoa(num, buf, 10);
|
|
||||||
return concat(buf, strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(int num)
|
|
||||||
{
|
|
||||||
char buf[7];
|
|
||||||
itoa(num, buf, 10);
|
|
||||||
return concat(buf, strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(unsigned int num)
|
|
||||||
{
|
|
||||||
char buf[6];
|
|
||||||
utoa(num, buf, 10);
|
|
||||||
return concat(buf, strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(long num)
|
|
||||||
{
|
|
||||||
char buf[12];
|
|
||||||
ltoa(num, buf, 10);
|
|
||||||
return concat(buf, strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::concat(unsigned long num)
|
|
||||||
{
|
|
||||||
char buf[11];
|
|
||||||
ultoa(num, buf, 10);
|
|
||||||
return concat(buf, strlen(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Concatenate */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, char c)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(c)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(num)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, int num)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(num)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(num)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, long num)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(num)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
|
|
||||||
{
|
|
||||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
|
||||||
if (!a.concat(num)) a.invalidate();
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Comparison */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
int String::compareTo(const String &s) const
|
|
||||||
{
|
|
||||||
if (!buffer || !s.buffer) {
|
|
||||||
if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
|
|
||||||
if (buffer && len > 0) return *(unsigned char *)buffer;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return strcmp(buffer, s.buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::equals(const String &s2) const
|
|
||||||
{
|
|
||||||
return (len == s2.len && compareTo(s2) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::equals(const char *cstr) const
|
|
||||||
{
|
|
||||||
if (len == 0) return (cstr == NULL || *cstr == 0);
|
|
||||||
if (cstr == NULL) return buffer[0] == 0;
|
|
||||||
return strcmp(buffer, cstr) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::operator<(const String &rhs) const
|
|
||||||
{
|
|
||||||
return compareTo(rhs) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::operator>(const String &rhs) const
|
|
||||||
{
|
|
||||||
return compareTo(rhs) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::operator<=(const String &rhs) const
|
|
||||||
{
|
|
||||||
return compareTo(rhs) <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::operator>=(const String &rhs) const
|
|
||||||
{
|
|
||||||
return compareTo(rhs) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::equalsIgnoreCase( const String &s2 ) const
|
|
||||||
{
|
|
||||||
if (this == &s2) return 1;
|
|
||||||
if (len != s2.len) return 0;
|
|
||||||
if (len == 0) return 1;
|
|
||||||
const char *p1 = buffer;
|
|
||||||
const char *p2 = s2.buffer;
|
|
||||||
while (*p1) {
|
|
||||||
if (tolower(*p1++) != tolower(*p2++)) return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::startsWith( const String &s2 ) const
|
|
||||||
{
|
|
||||||
if (len < s2.len) return 0;
|
|
||||||
return startsWith(s2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::startsWith( const String &s2, unsigned int offset ) const
|
|
||||||
{
|
|
||||||
if (offset > len - s2.len || !buffer || !s2.buffer) return 0;
|
|
||||||
return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char String::endsWith( const String &s2 ) const
|
|
||||||
{
|
|
||||||
if ( len < s2.len || !buffer || !s2.buffer) return 0;
|
|
||||||
return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Character Access */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
char String::charAt(unsigned int loc) const
|
|
||||||
{
|
|
||||||
return operator[](loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::setCharAt(unsigned int loc, char c)
|
|
||||||
{
|
|
||||||
if (loc < len) buffer[loc] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
char & String::operator[](unsigned int index)
|
|
||||||
{
|
|
||||||
static char dummy_writable_char;
|
|
||||||
if (index >= len || !buffer) {
|
|
||||||
dummy_writable_char = 0;
|
|
||||||
return dummy_writable_char;
|
|
||||||
}
|
|
||||||
return buffer[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
char String::operator[]( unsigned int index ) const
|
|
||||||
{
|
|
||||||
if (index >= len || !buffer) return 0;
|
|
||||||
return buffer[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
|
|
||||||
{
|
|
||||||
if (!bufsize || !buf) return;
|
|
||||||
if (index >= len) {
|
|
||||||
buf[0] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
unsigned int n = bufsize - 1;
|
|
||||||
if (n > len - index) n = len - index;
|
|
||||||
strncpy((char *)buf, buffer + index, n);
|
|
||||||
buf[n] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Search */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
int String::indexOf(char c) const
|
|
||||||
{
|
|
||||||
return indexOf(c, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::indexOf( char ch, unsigned int fromIndex ) const
|
|
||||||
{
|
|
||||||
if (fromIndex >= len) return -1;
|
|
||||||
const char* temp = strchr(buffer + fromIndex, ch);
|
|
||||||
if (temp == NULL) return -1;
|
|
||||||
return temp - buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::indexOf(const String &s2) const
|
|
||||||
{
|
|
||||||
return indexOf(s2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::indexOf(const String &s2, unsigned int fromIndex) const
|
|
||||||
{
|
|
||||||
if (fromIndex >= len) return -1;
|
|
||||||
const char *found = strstr(buffer + fromIndex, s2.buffer);
|
|
||||||
if (found == NULL) return -1;
|
|
||||||
return found - buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::lastIndexOf( char theChar ) const
|
|
||||||
{
|
|
||||||
return lastIndexOf(theChar, len - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::lastIndexOf(char ch, unsigned int fromIndex) const
|
|
||||||
{
|
|
||||||
if (fromIndex >= len) return -1;
|
|
||||||
char tempchar = buffer[fromIndex + 1];
|
|
||||||
buffer[fromIndex + 1] = '\0';
|
|
||||||
char* temp = strrchr( buffer, ch );
|
|
||||||
buffer[fromIndex + 1] = tempchar;
|
|
||||||
if (temp == NULL) return -1;
|
|
||||||
return temp - buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::lastIndexOf(const String &s2) const
|
|
||||||
{
|
|
||||||
return lastIndexOf(s2, len - s2.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
|
|
||||||
{
|
|
||||||
if (s2.len == 0 || len == 0 || s2.len > len) return -1;
|
|
||||||
if (fromIndex >= len) fromIndex = len - 1;
|
|
||||||
int found = -1;
|
|
||||||
for (char *p = buffer; p <= buffer + fromIndex; p++) {
|
|
||||||
p = strstr(p, s2.buffer);
|
|
||||||
if (!p) break;
|
|
||||||
if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
String String::substring( unsigned int left ) const
|
|
||||||
{
|
|
||||||
return substring(left, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
String String::substring(unsigned int left, unsigned int right) const
|
|
||||||
{
|
|
||||||
if (left > right) {
|
|
||||||
unsigned int temp = right;
|
|
||||||
right = left;
|
|
||||||
left = temp;
|
|
||||||
}
|
|
||||||
String out;
|
|
||||||
if (left > len) return out;
|
|
||||||
if (right > len) right = len;
|
|
||||||
char temp = buffer[right]; // save the replaced character
|
|
||||||
buffer[right] = '\0';
|
|
||||||
out = buffer + left; // pointer arithmetic
|
|
||||||
buffer[right] = temp; //restore character
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Modification */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
void String::replace(char find, char replace)
|
|
||||||
{
|
|
||||||
if (!buffer) return;
|
|
||||||
for (char *p = buffer; *p; p++) {
|
|
||||||
if (*p == find) *p = replace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::replace(const String& find, const String& replace)
|
|
||||||
{
|
|
||||||
if (len == 0 || find.len == 0) return;
|
|
||||||
int diff = replace.len - find.len;
|
|
||||||
char *readFrom = buffer;
|
|
||||||
char *foundAt;
|
|
||||||
if (diff == 0) {
|
|
||||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
|
||||||
memcpy(foundAt, replace.buffer, replace.len);
|
|
||||||
readFrom = foundAt + replace.len;
|
|
||||||
}
|
|
||||||
} else if (diff < 0) {
|
|
||||||
char *writeTo = buffer;
|
|
||||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
|
||||||
unsigned int n = foundAt - readFrom;
|
|
||||||
memcpy(writeTo, readFrom, n);
|
|
||||||
writeTo += n;
|
|
||||||
memcpy(writeTo, replace.buffer, replace.len);
|
|
||||||
writeTo += replace.len;
|
|
||||||
readFrom = foundAt + find.len;
|
|
||||||
len += diff;
|
|
||||||
}
|
|
||||||
strcpy(writeTo, readFrom);
|
|
||||||
} else {
|
|
||||||
unsigned int size = len; // compute size needed for result
|
|
||||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
|
||||||
readFrom = foundAt + find.len;
|
|
||||||
size += diff;
|
|
||||||
}
|
|
||||||
if (size == len) return;
|
|
||||||
if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!
|
|
||||||
int index = len - 1;
|
|
||||||
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
|
|
||||||
readFrom = buffer + index + find.len;
|
|
||||||
memmove(readFrom + diff, readFrom, len - (readFrom - buffer));
|
|
||||||
len += diff;
|
|
||||||
buffer[len] = 0;
|
|
||||||
memcpy(buffer + index, replace.buffer, replace.len);
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::toLowerCase(void)
|
|
||||||
{
|
|
||||||
if (!buffer) return;
|
|
||||||
for (char *p = buffer; *p; p++) {
|
|
||||||
*p = tolower(*p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::toUpperCase(void)
|
|
||||||
{
|
|
||||||
if (!buffer) return;
|
|
||||||
for (char *p = buffer; *p; p++) {
|
|
||||||
*p = toupper(*p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void String::trim(void)
|
|
||||||
{
|
|
||||||
if (!buffer || len == 0) return;
|
|
||||||
char *begin = buffer;
|
|
||||||
while (isspace(*begin)) begin++;
|
|
||||||
char *end = buffer + len - 1;
|
|
||||||
while (isspace(*end) && end >= begin) end--;
|
|
||||||
len = end + 1 - begin;
|
|
||||||
if (begin > buffer) memcpy(buffer, begin, len);
|
|
||||||
buffer[len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************/
|
|
||||||
/* Parsing / Conversion */
|
|
||||||
/*********************************************/
|
|
||||||
|
|
||||||
long String::toInt(void) const
|
|
||||||
{
|
|
||||||
if (buffer) return atol(buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,205 +0,0 @@
|
||||||
/*
|
|
||||||
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);
|
|
||||||
#ifdef __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);
|
|
||||||
~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);
|
|
||||||
#ifdef __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);
|
|
||||||
|
|
||||||
// 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);}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// 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);}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
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 toLowerCase(void);
|
|
||||||
void toUpperCase(void);
|
|
||||||
void trim(void);
|
|
||||||
|
|
||||||
// parsing/conversion
|
|
||||||
long toInt(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')
|
|
||||||
unsigned char flags; // unused, for future features
|
|
||||||
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);
|
|
||||||
#ifdef __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) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
#endif // String_class_h
|
|
|
@ -1,298 +0,0 @@
|
||||||
/*
|
|
||||||
TwoWire.cpp - TWI/I2C library for Wiring & Arduino
|
|
||||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
|
||||||
|
|
||||||
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "twi.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "Wire.h"
|
|
||||||
|
|
||||||
// Initialize Class Variables //////////////////////////////////////////////////
|
|
||||||
|
|
||||||
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
|
|
||||||
uint8_t TwoWire::rxBufferIndex = 0;
|
|
||||||
uint8_t TwoWire::rxBufferLength = 0;
|
|
||||||
|
|
||||||
uint8_t TwoWire::txAddress = 0;
|
|
||||||
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
|
|
||||||
uint8_t TwoWire::txBufferIndex = 0;
|
|
||||||
uint8_t TwoWire::txBufferLength = 0;
|
|
||||||
|
|
||||||
uint8_t TwoWire::transmitting = 0;
|
|
||||||
void (*TwoWire::user_onRequest)(void);
|
|
||||||
void (*TwoWire::user_onReceive)(int);
|
|
||||||
|
|
||||||
// Constructors ////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
TwoWire::TwoWire()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public Methods //////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void TwoWire::begin(void)
|
|
||||||
{
|
|
||||||
rxBufferIndex = 0;
|
|
||||||
rxBufferLength = 0;
|
|
||||||
|
|
||||||
txBufferIndex = 0;
|
|
||||||
txBufferLength = 0;
|
|
||||||
|
|
||||||
twi_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TwoWire::begin(uint8_t address)
|
|
||||||
{
|
|
||||||
twi_setAddress(address);
|
|
||||||
twi_attachSlaveTxEvent(onRequestService);
|
|
||||||
twi_attachSlaveRxEvent(onReceiveService);
|
|
||||||
begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TwoWire::begin(int address)
|
|
||||||
{
|
|
||||||
begin((uint8_t)address);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
|
|
||||||
{
|
|
||||||
// clamp to buffer length
|
|
||||||
if(quantity > BUFFER_LENGTH){
|
|
||||||
quantity = BUFFER_LENGTH;
|
|
||||||
}
|
|
||||||
// perform blocking read into buffer
|
|
||||||
uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
|
|
||||||
// set rx buffer iterator vars
|
|
||||||
rxBufferIndex = 0;
|
|
||||||
rxBufferLength = read;
|
|
||||||
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
|
|
||||||
{
|
|
||||||
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TwoWire::requestFrom(int address, int quantity)
|
|
||||||
{
|
|
||||||
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
|
|
||||||
{
|
|
||||||
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TwoWire::beginTransmission(uint8_t address)
|
|
||||||
{
|
|
||||||
// indicate that we are transmitting
|
|
||||||
transmitting = 1;
|
|
||||||
// set address of targeted slave
|
|
||||||
txAddress = address;
|
|
||||||
// reset tx buffer iterator vars
|
|
||||||
txBufferIndex = 0;
|
|
||||||
txBufferLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TwoWire::beginTransmission(int address)
|
|
||||||
{
|
|
||||||
beginTransmission((uint8_t)address);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Originally, 'endTransmission' was an f(void) function.
|
|
||||||
// It has been modified to take one parameter indicating
|
|
||||||
// whether or not a STOP should be performed on the bus.
|
|
||||||
// Calling endTransmission(false) allows a sketch to
|
|
||||||
// perform a repeated start.
|
|
||||||
//
|
|
||||||
// WARNING: Nothing in the library keeps track of whether
|
|
||||||
// the bus tenure has been properly ended with a STOP. It
|
|
||||||
// is very possible to leave the bus in a hung state if
|
|
||||||
// no call to endTransmission(true) is made. Some I2C
|
|
||||||
// devices will behave oddly if they do not see a STOP.
|
|
||||||
//
|
|
||||||
uint8_t TwoWire::endTransmission(uint8_t sendStop)
|
|
||||||
{
|
|
||||||
// transmit buffer (blocking)
|
|
||||||
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
|
|
||||||
// reset tx buffer iterator vars
|
|
||||||
txBufferIndex = 0;
|
|
||||||
txBufferLength = 0;
|
|
||||||
// indicate that we are done transmitting
|
|
||||||
transmitting = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This provides backwards compatibility with the original
|
|
||||||
// definition, and expected behaviour, of endTransmission
|
|
||||||
//
|
|
||||||
uint8_t TwoWire::endTransmission(void)
|
|
||||||
{
|
|
||||||
return endTransmission(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be called in:
|
|
||||||
// slave tx event callback
|
|
||||||
// or after beginTransmission(address)
|
|
||||||
size_t TwoWire::write(uint8_t data)
|
|
||||||
{
|
|
||||||
if(transmitting){
|
|
||||||
// in master transmitter mode
|
|
||||||
// don't bother if buffer is full
|
|
||||||
if(txBufferLength >= BUFFER_LENGTH){
|
|
||||||
setWriteError();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// put byte in tx buffer
|
|
||||||
txBuffer[txBufferIndex] = data;
|
|
||||||
++txBufferIndex;
|
|
||||||
// update amount in buffer
|
|
||||||
txBufferLength = txBufferIndex;
|
|
||||||
}else{
|
|
||||||
// in slave send mode
|
|
||||||
// reply to master
|
|
||||||
twi_transmit(&data, 1);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be called in:
|
|
||||||
// slave tx event callback
|
|
||||||
// or after beginTransmission(address)
|
|
||||||
size_t TwoWire::write(const uint8_t *data, size_t quantity)
|
|
||||||
{
|
|
||||||
if(transmitting){
|
|
||||||
// in master transmitter mode
|
|
||||||
for(size_t i = 0; i < quantity; ++i){
|
|
||||||
write(data[i]);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
// in slave send mode
|
|
||||||
// reply to master
|
|
||||||
twi_transmit(data, quantity);
|
|
||||||
}
|
|
||||||
return quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be called in:
|
|
||||||
// slave rx event callback
|
|
||||||
// or after requestFrom(address, numBytes)
|
|
||||||
int TwoWire::available(void)
|
|
||||||
{
|
|
||||||
return rxBufferLength - rxBufferIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be called in:
|
|
||||||
// slave rx event callback
|
|
||||||
// or after requestFrom(address, numBytes)
|
|
||||||
int TwoWire::read(void)
|
|
||||||
{
|
|
||||||
int value = -1;
|
|
||||||
|
|
||||||
// get each successive byte on each call
|
|
||||||
if(rxBufferIndex < rxBufferLength){
|
|
||||||
value = rxBuffer[rxBufferIndex];
|
|
||||||
++rxBufferIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be called in:
|
|
||||||
// slave rx event callback
|
|
||||||
// or after requestFrom(address, numBytes)
|
|
||||||
int TwoWire::peek(void)
|
|
||||||
{
|
|
||||||
int value = -1;
|
|
||||||
|
|
||||||
if(rxBufferIndex < rxBufferLength){
|
|
||||||
value = rxBuffer[rxBufferIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TwoWire::flush(void)
|
|
||||||
{
|
|
||||||
// XXX: to be implemented.
|
|
||||||
}
|
|
||||||
|
|
||||||
// behind the scenes function that is called when data is received
|
|
||||||
void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
|
|
||||||
{
|
|
||||||
// don't bother if user hasn't registered a callback
|
|
||||||
if(!user_onReceive){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// don't bother if rx buffer is in use by a master requestFrom() op
|
|
||||||
// i know this drops data, but it allows for slight stupidity
|
|
||||||
// meaning, they may not have read all the master requestFrom() data yet
|
|
||||||
if(rxBufferIndex < rxBufferLength){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// copy twi rx buffer into local read buffer
|
|
||||||
// this enables new reads to happen in parallel
|
|
||||||
for(uint8_t i = 0; i < numBytes; ++i){
|
|
||||||
rxBuffer[i] = inBytes[i];
|
|
||||||
}
|
|
||||||
// set rx iterator vars
|
|
||||||
rxBufferIndex = 0;
|
|
||||||
rxBufferLength = numBytes;
|
|
||||||
// alert user program
|
|
||||||
user_onReceive(numBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// behind the scenes function that is called when data is requested
|
|
||||||
void TwoWire::onRequestService(void)
|
|
||||||
{
|
|
||||||
// don't bother if user hasn't registered a callback
|
|
||||||
if(!user_onRequest){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// reset tx buffer iterator vars
|
|
||||||
// !!! this will kill any pending pre-master sendTo() activity
|
|
||||||
txBufferIndex = 0;
|
|
||||||
txBufferLength = 0;
|
|
||||||
// alert user program
|
|
||||||
user_onRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets function called on slave write
|
|
||||||
void TwoWire::onReceive( void (*function)(int) )
|
|
||||||
{
|
|
||||||
user_onReceive = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets function called on slave read
|
|
||||||
void TwoWire::onRequest( void (*function)(void) )
|
|
||||||
{
|
|
||||||
user_onRequest = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preinstantiate Objects //////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
TwoWire Wire = TwoWire();
|
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
TwoWire.h - TWI/I2C library for Arduino & Wiring
|
|
||||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
|
||||||
|
|
||||||
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TwoWire_h
|
|
||||||
#define TwoWire_h
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "Stream.h"
|
|
||||||
|
|
||||||
#define BUFFER_LENGTH 32
|
|
||||||
|
|
||||||
class TwoWire : public Stream
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
static uint8_t rxBuffer[];
|
|
||||||
static uint8_t rxBufferIndex;
|
|
||||||
static uint8_t rxBufferLength;
|
|
||||||
|
|
||||||
static uint8_t txAddress;
|
|
||||||
static uint8_t txBuffer[];
|
|
||||||
static uint8_t txBufferIndex;
|
|
||||||
static uint8_t txBufferLength;
|
|
||||||
|
|
||||||
static uint8_t transmitting;
|
|
||||||
static void (*user_onRequest)(void);
|
|
||||||
static void (*user_onReceive)(int);
|
|
||||||
static void onRequestService(void);
|
|
||||||
static void onReceiveService(uint8_t*, int);
|
|
||||||
public:
|
|
||||||
TwoWire();
|
|
||||||
void begin();
|
|
||||||
void begin(uint8_t);
|
|
||||||
void begin(int);
|
|
||||||
void beginTransmission(uint8_t);
|
|
||||||
void beginTransmission(int);
|
|
||||||
uint8_t endTransmission(void);
|
|
||||||
uint8_t endTransmission(uint8_t);
|
|
||||||
uint8_t requestFrom(uint8_t, uint8_t);
|
|
||||||
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
|
|
||||||
uint8_t requestFrom(int, int);
|
|
||||||
uint8_t requestFrom(int, int, int);
|
|
||||||
virtual size_t write(uint8_t);
|
|
||||||
virtual size_t write(const uint8_t *, size_t);
|
|
||||||
virtual int available(void);
|
|
||||||
virtual int read(void);
|
|
||||||
virtual int peek(void);
|
|
||||||
virtual void flush(void);
|
|
||||||
void onReceive( void (*)(int) );
|
|
||||||
void onRequest( void (*)(void) );
|
|
||||||
|
|
||||||
inline size_t write(unsigned long n) { return write((uint8_t)n); }
|
|
||||||
inline size_t write(long n) { return write((uint8_t)n); }
|
|
||||||
inline size_t write(unsigned int n) { return write((uint8_t)n); }
|
|
||||||
inline size_t write(int n) { return write((uint8_t)n); }
|
|
||||||
using Print::write;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern TwoWire Wire;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
#include <new.h>
|
|
||||||
|
|
||||||
void * operator new(size_t size)
|
|
||||||
{
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void * operator new[](size_t size)
|
|
||||||
{
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete(void * ptr)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete[](void * ptr)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
|
|
||||||
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
|
|
||||||
void __cxa_guard_abort (__guard *) {};
|
|
||||||
|
|
||||||
void __cxa_pure_virtual(void) {};
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
|
|
||||||
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef NEW_H
|
|
||||||
#define NEW_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
void * operator new(size_t size);
|
|
||||||
void * operator new[](size_t size);
|
|
||||||
void operator delete(void * ptr);
|
|
||||||
void operator delete[](void * ptr);
|
|
||||||
|
|
||||||
__extension__ typedef int __guard __attribute__((mode (__DI__)));
|
|
||||||
|
|
||||||
extern "C" int __cxa_guard_acquire(__guard *);
|
|
||||||
extern "C" void __cxa_guard_release (__guard *);
|
|
||||||
extern "C" void __cxa_guard_abort (__guard *);
|
|
||||||
|
|
||||||
extern "C" void __cxa_pure_virtual(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,527 +0,0 @@
|
||||||
/*
|
|
||||||
twi.c - TWI/I2C library for Wiring & Arduino
|
|
||||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
|
||||||
|
|
||||||
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <compat/twi.h>
|
|
||||||
#include "Arduino.h" // for digitalWrite
|
|
||||||
|
|
||||||
#ifndef cbi
|
|
||||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef sbi
|
|
||||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pins_arduino.h"
|
|
||||||
#include "twi.h"
|
|
||||||
|
|
||||||
static volatile uint8_t twi_state;
|
|
||||||
static volatile uint8_t twi_slarw;
|
|
||||||
static volatile uint8_t twi_sendStop; // should the transaction end with a stop
|
|
||||||
static volatile uint8_t twi_inRepStart; // in the middle of a repeated start
|
|
||||||
|
|
||||||
static void (*twi_onSlaveTransmit)(void);
|
|
||||||
static void (*twi_onSlaveReceive)(uint8_t*, int);
|
|
||||||
|
|
||||||
static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
|
|
||||||
static volatile uint8_t twi_masterBufferIndex;
|
|
||||||
static volatile uint8_t twi_masterBufferLength;
|
|
||||||
|
|
||||||
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
|
|
||||||
static volatile uint8_t twi_txBufferIndex;
|
|
||||||
static volatile uint8_t twi_txBufferLength;
|
|
||||||
|
|
||||||
static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
|
|
||||||
static volatile uint8_t twi_rxBufferIndex;
|
|
||||||
|
|
||||||
static volatile uint8_t twi_error;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_init
|
|
||||||
* Desc readys twi pins and sets twi bitrate
|
|
||||||
* Input none
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_init(void)
|
|
||||||
{
|
|
||||||
// initialize state
|
|
||||||
twi_state = TWI_READY;
|
|
||||||
twi_sendStop = true; // default value
|
|
||||||
twi_inRepStart = false;
|
|
||||||
|
|
||||||
// activate internal pullups for twi.
|
|
||||||
digitalWrite(SDA, 1);
|
|
||||||
digitalWrite(SCL, 1);
|
|
||||||
|
|
||||||
// initialize twi prescaler and bit rate
|
|
||||||
cbi(TWSR, TWPS0);
|
|
||||||
cbi(TWSR, TWPS1);
|
|
||||||
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
|
|
||||||
|
|
||||||
/* twi bit rate formula from atmega128 manual pg 204
|
|
||||||
SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
|
|
||||||
note: TWBR should be 10 or higher for master mode
|
|
||||||
It is 72 for a 16mhz Wiring board with 100kHz TWI */
|
|
||||||
|
|
||||||
// enable twi module, acks, and twi interrupt
|
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_slaveInit
|
|
||||||
* Desc sets slave address and enables interrupt
|
|
||||||
* Input none
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_setAddress(uint8_t address)
|
|
||||||
{
|
|
||||||
// set twi slave address (skip over TWGCE bit)
|
|
||||||
TWAR = address << 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_readFrom
|
|
||||||
* Desc attempts to become twi bus master and read a
|
|
||||||
* series of bytes from a device on the bus
|
|
||||||
* Input address: 7bit i2c device address
|
|
||||||
* data: pointer to byte array
|
|
||||||
* length: number of bytes to read into array
|
|
||||||
* sendStop: Boolean indicating whether to send a stop at the end
|
|
||||||
* Output number of bytes read
|
|
||||||
*/
|
|
||||||
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
|
|
||||||
{
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
// ensure data will fit into buffer
|
|
||||||
if(TWI_BUFFER_LENGTH < length){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until twi is ready, become master receiver
|
|
||||||
while(TWI_READY != twi_state){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
twi_state = TWI_MRX;
|
|
||||||
twi_sendStop = sendStop;
|
|
||||||
// reset error state (0xFF.. no error occured)
|
|
||||||
twi_error = 0xFF;
|
|
||||||
|
|
||||||
// initialize buffer iteration vars
|
|
||||||
twi_masterBufferIndex = 0;
|
|
||||||
twi_masterBufferLength = length-1; // This is not intuitive, read on...
|
|
||||||
// On receive, the previously configured ACK/NACK setting is transmitted in
|
|
||||||
// response to the received byte before the interrupt is signalled.
|
|
||||||
// Therefor we must actually set NACK when the _next_ to last byte is
|
|
||||||
// received, causing that NACK to be sent in response to receiving the last
|
|
||||||
// expected byte of data.
|
|
||||||
|
|
||||||
// build sla+w, slave device address + w bit
|
|
||||||
twi_slarw = TW_READ;
|
|
||||||
twi_slarw |= address << 1;
|
|
||||||
|
|
||||||
if (true == twi_inRepStart) {
|
|
||||||
// if we're in the repeated start state, then we've already sent the start,
|
|
||||||
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
|
|
||||||
// We need to remove ourselves from the repeated start state before we enable interrupts,
|
|
||||||
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
|
|
||||||
// up. Also, don't enable the START interrupt. There may be one pending from the
|
|
||||||
// repeated start that we sent outselves, and that would really confuse things.
|
|
||||||
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
|
|
||||||
TWDR = twi_slarw;
|
|
||||||
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// send start condition
|
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
|
|
||||||
|
|
||||||
// wait for read operation to complete
|
|
||||||
while(TWI_MRX == twi_state){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twi_masterBufferIndex < length)
|
|
||||||
length = twi_masterBufferIndex;
|
|
||||||
|
|
||||||
// copy twi buffer to data
|
|
||||||
for(i = 0; i < length; ++i){
|
|
||||||
data[i] = twi_masterBuffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_writeTo
|
|
||||||
* Desc attempts to become twi bus master and write a
|
|
||||||
* series of bytes to a device on the bus
|
|
||||||
* Input address: 7bit i2c device address
|
|
||||||
* data: pointer to byte array
|
|
||||||
* length: number of bytes in array
|
|
||||||
* wait: boolean indicating to wait for write or not
|
|
||||||
* sendStop: boolean indicating whether or not to send a stop at the end
|
|
||||||
* Output 0 .. success
|
|
||||||
* 1 .. length to long for buffer
|
|
||||||
* 2 .. address send, NACK received
|
|
||||||
* 3 .. data send, NACK received
|
|
||||||
* 4 .. other twi error (lost bus arbitration, bus error, ..)
|
|
||||||
*/
|
|
||||||
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
|
|
||||||
{
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
// ensure data will fit into buffer
|
|
||||||
if(TWI_BUFFER_LENGTH < length){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until twi is ready, become master transmitter
|
|
||||||
while(TWI_READY != twi_state){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
twi_state = TWI_MTX;
|
|
||||||
twi_sendStop = sendStop;
|
|
||||||
// reset error state (0xFF.. no error occured)
|
|
||||||
twi_error = 0xFF;
|
|
||||||
|
|
||||||
// initialize buffer iteration vars
|
|
||||||
twi_masterBufferIndex = 0;
|
|
||||||
twi_masterBufferLength = length;
|
|
||||||
|
|
||||||
// copy data to twi buffer
|
|
||||||
for(i = 0; i < length; ++i){
|
|
||||||
twi_masterBuffer[i] = data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// build sla+w, slave device address + w bit
|
|
||||||
twi_slarw = TW_WRITE;
|
|
||||||
twi_slarw |= address << 1;
|
|
||||||
|
|
||||||
// if we're in a repeated start, then we've already sent the START
|
|
||||||
// in the ISR. Don't do it again.
|
|
||||||
//
|
|
||||||
if (true == twi_inRepStart) {
|
|
||||||
// if we're in the repeated start state, then we've already sent the start,
|
|
||||||
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
|
|
||||||
// We need to remove ourselves from the repeated start state before we enable interrupts,
|
|
||||||
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
|
|
||||||
// up. Also, don't enable the START interrupt. There may be one pending from the
|
|
||||||
// repeated start that we sent outselves, and that would really confuse things.
|
|
||||||
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
|
|
||||||
TWDR = twi_slarw;
|
|
||||||
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// send start condition
|
|
||||||
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs
|
|
||||||
|
|
||||||
// wait for write operation to complete
|
|
||||||
while(wait && (TWI_MTX == twi_state)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (twi_error == 0xFF)
|
|
||||||
return 0; // success
|
|
||||||
else if (twi_error == TW_MT_SLA_NACK)
|
|
||||||
return 2; // error: address send, nack received
|
|
||||||
else if (twi_error == TW_MT_DATA_NACK)
|
|
||||||
return 3; // error: data send, nack received
|
|
||||||
else
|
|
||||||
return 4; // other twi error
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_transmit
|
|
||||||
* Desc fills slave tx buffer with data
|
|
||||||
* must be called in slave tx event callback
|
|
||||||
* Input data: pointer to byte array
|
|
||||||
* length: number of bytes in array
|
|
||||||
* Output 1 length too long for buffer
|
|
||||||
* 2 not slave transmitter
|
|
||||||
* 0 ok
|
|
||||||
*/
|
|
||||||
uint8_t twi_transmit(const uint8_t* data, uint8_t length)
|
|
||||||
{
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
// ensure data will fit into buffer
|
|
||||||
if(TWI_BUFFER_LENGTH < length){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure we are currently a slave transmitter
|
|
||||||
if(TWI_STX != twi_state){
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set length and copy data into tx buffer
|
|
||||||
twi_txBufferLength = length;
|
|
||||||
for(i = 0; i < length; ++i){
|
|
||||||
twi_txBuffer[i] = data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_attachSlaveRxEvent
|
|
||||||
* Desc sets function called before a slave read operation
|
|
||||||
* Input function: callback function to use
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
|
|
||||||
{
|
|
||||||
twi_onSlaveReceive = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_attachSlaveTxEvent
|
|
||||||
* Desc sets function called before a slave write operation
|
|
||||||
* Input function: callback function to use
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_attachSlaveTxEvent( void (*function)(void) )
|
|
||||||
{
|
|
||||||
twi_onSlaveTransmit = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_reply
|
|
||||||
* Desc sends byte or readys receive line
|
|
||||||
* Input ack: byte indicating to ack or to nack
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_reply(uint8_t ack)
|
|
||||||
{
|
|
||||||
// transmit master read ready signal, with or without ack
|
|
||||||
if(ack){
|
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
|
|
||||||
}else{
|
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_stop
|
|
||||||
* Desc relinquishes bus master status
|
|
||||||
* Input none
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_stop(void)
|
|
||||||
{
|
|
||||||
// send stop condition
|
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
|
|
||||||
|
|
||||||
// wait for stop condition to be exectued on bus
|
|
||||||
// TWINT is not set after a stop condition!
|
|
||||||
while(TWCR & _BV(TWSTO)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update twi state
|
|
||||||
twi_state = TWI_READY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function twi_releaseBus
|
|
||||||
* Desc releases bus control
|
|
||||||
* Input none
|
|
||||||
* Output none
|
|
||||||
*/
|
|
||||||
void twi_releaseBus(void)
|
|
||||||
{
|
|
||||||
// release bus
|
|
||||||
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
|
|
||||||
|
|
||||||
// update twi state
|
|
||||||
twi_state = TWI_READY;
|
|
||||||
}
|
|
||||||
|
|
||||||
SIGNAL(TWI_vect)
|
|
||||||
{
|
|
||||||
switch(TW_STATUS){
|
|
||||||
// All Master
|
|
||||||
case TW_START: // sent start condition
|
|
||||||
case TW_REP_START: // sent repeated start condition
|
|
||||||
// copy device address and r/w bit to output register and ack
|
|
||||||
TWDR = twi_slarw;
|
|
||||||
twi_reply(1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Master Transmitter
|
|
||||||
case TW_MT_SLA_ACK: // slave receiver acked address
|
|
||||||
case TW_MT_DATA_ACK: // slave receiver acked data
|
|
||||||
// if there is data to send, send it, otherwise stop
|
|
||||||
if(twi_masterBufferIndex < twi_masterBufferLength){
|
|
||||||
// copy data to output register and ack
|
|
||||||
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
|
|
||||||
twi_reply(1);
|
|
||||||
}else{
|
|
||||||
if (twi_sendStop)
|
|
||||||
twi_stop();
|
|
||||||
else {
|
|
||||||
twi_inRepStart = true; // we're gonna send the START
|
|
||||||
// don't enable the interrupt. We'll generate the start, but we
|
|
||||||
// avoid handling the interrupt until we're in the next transaction,
|
|
||||||
// at the point where we would normally issue the start.
|
|
||||||
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
|
|
||||||
twi_state = TWI_READY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TW_MT_SLA_NACK: // address sent, nack received
|
|
||||||
twi_error = TW_MT_SLA_NACK;
|
|
||||||
twi_stop();
|
|
||||||
break;
|
|
||||||
case TW_MT_DATA_NACK: // data sent, nack received
|
|
||||||
twi_error = TW_MT_DATA_NACK;
|
|
||||||
twi_stop();
|
|
||||||
break;
|
|
||||||
case TW_MT_ARB_LOST: // lost bus arbitration
|
|
||||||
twi_error = TW_MT_ARB_LOST;
|
|
||||||
twi_releaseBus();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Master Receiver
|
|
||||||
case TW_MR_DATA_ACK: // data received, ack sent
|
|
||||||
// put byte into buffer
|
|
||||||
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
|
|
||||||
case TW_MR_SLA_ACK: // address sent, ack received
|
|
||||||
// ack if more bytes are expected, otherwise nack
|
|
||||||
if(twi_masterBufferIndex < twi_masterBufferLength){
|
|
||||||
twi_reply(1);
|
|
||||||
}else{
|
|
||||||
twi_reply(0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TW_MR_DATA_NACK: // data received, nack sent
|
|
||||||
// put final byte into buffer
|
|
||||||
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
|
|
||||||
if (twi_sendStop)
|
|
||||||
twi_stop();
|
|
||||||
else {
|
|
||||||
twi_inRepStart = true; // we're gonna send the START
|
|
||||||
// don't enable the interrupt. We'll generate the start, but we
|
|
||||||
// avoid handling the interrupt until we're in the next transaction,
|
|
||||||
// at the point where we would normally issue the start.
|
|
||||||
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
|
|
||||||
twi_state = TWI_READY;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TW_MR_SLA_NACK: // address sent, nack received
|
|
||||||
twi_stop();
|
|
||||||
break;
|
|
||||||
// TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
|
|
||||||
|
|
||||||
// Slave Receiver
|
|
||||||
case TW_SR_SLA_ACK: // addressed, returned ack
|
|
||||||
case TW_SR_GCALL_ACK: // addressed generally, returned ack
|
|
||||||
case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack
|
|
||||||
case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
|
|
||||||
// enter slave receiver mode
|
|
||||||
twi_state = TWI_SRX;
|
|
||||||
// indicate that rx buffer can be overwritten and ack
|
|
||||||
twi_rxBufferIndex = 0;
|
|
||||||
twi_reply(1);
|
|
||||||
break;
|
|
||||||
case TW_SR_DATA_ACK: // data received, returned ack
|
|
||||||
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
|
|
||||||
// if there is still room in the rx buffer
|
|
||||||
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
|
|
||||||
// put byte in buffer and ack
|
|
||||||
twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
|
|
||||||
twi_reply(1);
|
|
||||||
}else{
|
|
||||||
// otherwise nack
|
|
||||||
twi_reply(0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TW_SR_STOP: // stop or repeated start condition received
|
|
||||||
// put a null char after data if there's room
|
|
||||||
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
|
|
||||||
twi_rxBuffer[twi_rxBufferIndex] = '\0';
|
|
||||||
}
|
|
||||||
// sends ack and stops interface for clock stretching
|
|
||||||
twi_stop();
|
|
||||||
// callback to user defined callback
|
|
||||||
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
|
|
||||||
// since we submit rx buffer to "wire" library, we can reset it
|
|
||||||
twi_rxBufferIndex = 0;
|
|
||||||
// ack future responses and leave slave receiver state
|
|
||||||
twi_releaseBus();
|
|
||||||
break;
|
|
||||||
case TW_SR_DATA_NACK: // data received, returned nack
|
|
||||||
case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
|
|
||||||
// nack back at master
|
|
||||||
twi_reply(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Slave Transmitter
|
|
||||||
case TW_ST_SLA_ACK: // addressed, returned ack
|
|
||||||
case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
|
|
||||||
// enter slave transmitter mode
|
|
||||||
twi_state = TWI_STX;
|
|
||||||
// ready the tx buffer index for iteration
|
|
||||||
twi_txBufferIndex = 0;
|
|
||||||
// set tx buffer length to be zero, to verify if user changes it
|
|
||||||
twi_txBufferLength = 0;
|
|
||||||
// request for txBuffer to be filled and length to be set
|
|
||||||
// note: user must call twi_transmit(bytes, length) to do this
|
|
||||||
twi_onSlaveTransmit();
|
|
||||||
// if they didn't change buffer & length, initialize it
|
|
||||||
if(0 == twi_txBufferLength){
|
|
||||||
twi_txBufferLength = 1;
|
|
||||||
twi_txBuffer[0] = 0x00;
|
|
||||||
}
|
|
||||||
// transmit first byte from buffer, fall
|
|
||||||
case TW_ST_DATA_ACK: // byte sent, ack returned
|
|
||||||
// copy data to output register
|
|
||||||
TWDR = twi_txBuffer[twi_txBufferIndex++];
|
|
||||||
// if there is more to send, ack, otherwise nack
|
|
||||||
if(twi_txBufferIndex < twi_txBufferLength){
|
|
||||||
twi_reply(1);
|
|
||||||
}else{
|
|
||||||
twi_reply(0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TW_ST_DATA_NACK: // received nack, we are done
|
|
||||||
case TW_ST_LAST_DATA: // received ack, but we are done already!
|
|
||||||
// ack future responses
|
|
||||||
twi_reply(1);
|
|
||||||
// leave slave receiver state
|
|
||||||
twi_state = TWI_READY;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// All
|
|
||||||
case TW_NO_INFO: // no state information
|
|
||||||
break;
|
|
||||||
case TW_BUS_ERROR: // bus error, illegal stop/start
|
|
||||||
twi_error = TW_BUS_ERROR;
|
|
||||||
twi_stop();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
twi.h - TWI/I2C library for Wiring & Arduino
|
|
||||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef twi_h
|
|
||||||
#define twi_h
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
//#define ATMEGA8
|
|
||||||
|
|
||||||
#ifndef TWI_FREQ
|
|
||||||
#define TWI_FREQ 100000L
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TWI_BUFFER_LENGTH
|
|
||||||
#define TWI_BUFFER_LENGTH 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TWI_READY 0
|
|
||||||
#define TWI_MRX 1
|
|
||||||
#define TWI_MTX 2
|
|
||||||
#define TWI_SRX 3
|
|
||||||
#define TWI_STX 4
|
|
||||||
|
|
||||||
void twi_init(void);
|
|
||||||
void twi_setAddress(uint8_t);
|
|
||||||
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
|
|
||||||
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
|
|
||||||
uint8_t twi_transmit(const uint8_t*, uint8_t);
|
|
||||||
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
|
|
||||||
void twi_attachSlaveTxEvent( void (*)(void) );
|
|
||||||
void twi_reply(uint8_t);
|
|
||||||
void twi_stop(void);
|
|
||||||
void twi_releaseBus(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue