aboutsummaryrefslogtreecommitdiff
path: root/libraries
diff options
context:
space:
mode:
authorCristian Maglie <c.maglie@bug.st>2012-05-21 01:56:06 +0200
committerCristian Maglie <c.maglie@bug.st>2012-05-22 11:23:47 +0200
commit3786e337e0211ca1ef94b37b03e891adfb3b5f9a (patch)
treedd7f8f6fd396243460ec22da89bfbd71d552f484 /libraries
parent324023a67afd1691f12ead4388d7cdf1a9d1a6ef (diff)
parent9a8976ce56bcdb70815dd58c1764d9e5c3b6fe95 (diff)
Pre-merge upstream Arduino
Diffstat (limited to 'libraries')
-rwxr-xr-xlibraries/Ethernet/Dhcp.cpp158
-rwxr-xr-xlibraries/Ethernet/Dhcp.h19
-rw-r--r--libraries/Ethernet/Ethernet.cpp38
-rw-r--r--libraries/Ethernet/Ethernet.h3
-rw-r--r--libraries/Ethernet/EthernetClient.cpp2
-rw-r--r--libraries/Ethernet/EthernetUdp.cpp73
-rw-r--r--libraries/Ethernet/EthernetUdp.h1
-rw-r--r--libraries/Ethernet/examples/ChatServer/ChatServer.ino37
-rw-r--r--libraries/Ethernet/examples/PachubeClient/PachubeClient.ino78
-rw-r--r--libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino72
-rw-r--r--libraries/Ethernet/examples/TwitterClient/TwitterClient.ino15
-rw-r--r--libraries/Ethernet/examples/WebServer/WebServer.ino31
-rw-r--r--libraries/SD/utility/SdFatUtil.h2
-rwxr-xr-xlibraries/Servo/Servo.cpp4
-rw-r--r--libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino19
-rwxr-xr-xlibraries/Wire/Wire.cpp43
-rwxr-xr-xlibraries/Wire/Wire.h5
-rw-r--r--libraries/Wire/utility/twi.c75
-rwxr-xr-xlibraries/Wire/utility/twi.h4
19 files changed, 531 insertions, 148 deletions
diff --git a/libraries/Ethernet/Dhcp.cpp b/libraries/Ethernet/Dhcp.cpp
index 62bbfeb..e4d27f7 100755
--- a/libraries/Ethernet/Dhcp.cpp
+++ b/libraries/Ethernet/Dhcp.cpp
@@ -11,13 +11,33 @@
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
{
- uint8_t dhcp_state = STATE_DHCP_START;
- uint8_t messageType = 0;
-
- // zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
- memset(_dhcpMacAddr, 0, 26);
+ _dhcpLeaseTime=0;
+ _dhcpT1=0;
+ _dhcpT2=0;
+ _lastCheck=0;
+ _timeout = timeout;
+ _responseTimeout = responseTimeout;
+
+ // zero out _dhcpMacAddr
+ memset(_dhcpMacAddr, 0, 6);
+ reset_DHCP_lease();
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
+ _dhcp_state = STATE_DHCP_START;
+ return request_DHCP_lease();
+}
+
+void DhcpClass::reset_DHCP_lease(){
+ // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
+ memset(_dhcpLocalIp, 0, 20);
+}
+
+//return:0 on error, 1 if request is sent and response is received
+int DhcpClass::request_DHCP_lease(){
+
+ uint8_t messageType = 0;
+
+
// Pick an initial transaction ID
_dhcpTransactionId = random(1UL, 2000UL);
@@ -35,55 +55,75 @@ int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long
unsigned long startTime = millis();
- while(dhcp_state != STATE_DHCP_LEASED)
+ while(_dhcp_state != STATE_DHCP_LEASED)
{
- if(dhcp_state == STATE_DHCP_START)
+ if(_dhcp_state == STATE_DHCP_START)
{
_dhcpTransactionId++;
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
- dhcp_state = STATE_DHCP_DISCOVER;
+ _dhcp_state = STATE_DHCP_DISCOVER;
+ }
+ else if(_dhcp_state == STATE_DHCP_REREQUEST){
+ _dhcpTransactionId++;
+ send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
+ _dhcp_state = STATE_DHCP_REQUEST;
}
- else if(dhcp_state == STATE_DHCP_DISCOVER)
+ else if(_dhcp_state == STATE_DHCP_DISCOVER)
{
uint32_t respId;
- messageType = parseDHCPResponse(responseTimeout, respId);
+ messageType = parseDHCPResponse(_responseTimeout, respId);
if(messageType == DHCP_OFFER)
{
// We'll use the transaction ID that the offer came with,
// rather than the one we were up to
_dhcpTransactionId = respId;
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
- dhcp_state = STATE_DHCP_REQUEST;
+ _dhcp_state = STATE_DHCP_REQUEST;
}
}
- else if(dhcp_state == STATE_DHCP_REQUEST)
+ else if(_dhcp_state == STATE_DHCP_REQUEST)
{
uint32_t respId;
- messageType = parseDHCPResponse(responseTimeout, respId);
+ messageType = parseDHCPResponse(_responseTimeout, respId);
if(messageType == DHCP_ACK)
{
- dhcp_state = STATE_DHCP_LEASED;
+ _dhcp_state = STATE_DHCP_LEASED;
result = 1;
+ //use default lease time if we didn't get it
+ if(_dhcpLeaseTime == 0){
+ _dhcpLeaseTime = DEFAULT_LEASE;
+ }
+ //calculate T1 & T2 if we didn't get it
+ if(_dhcpT1 == 0){
+ //T1 should be 50% of _dhcpLeaseTime
+ _dhcpT1 = _dhcpLeaseTime >> 1;
+ }
+ if(_dhcpT2 == 0){
+ //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
+ _dhcpT2 = _dhcpT1 << 1;
+ }
+ _renewInSec = _dhcpT1;
+ _rebindInSec = _dhcpT2;
}
else if(messageType == DHCP_NAK)
- dhcp_state = STATE_DHCP_START;
+ _dhcp_state = STATE_DHCP_START;
}
if(messageType == 255)
{
messageType = 0;
- dhcp_state = STATE_DHCP_START;
+ _dhcp_state = STATE_DHCP_START;
}
- if(result != 1 && ((millis() - startTime) > timeout))
+ if(result != 1 && ((millis() - startTime) > _timeout))
break;
}
// We're done with the socket now
_dhcpUdpSocket.stop();
_dhcpTransactionId++;
-
+
return result;
}
@@ -302,8 +342,26 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
}
}
break;
-
+
+ case dhcpT1value :
+ opt_len = _dhcpUdpSocket.read();
+ _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
+ _dhcpT1 = ntohl(_dhcpT1);
+ break;
+
+ case dhcpT2value :
+ opt_len = _dhcpUdpSocket.read();
+ _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
+ _dhcpT2 = ntohl(_dhcpT2);
+ break;
+
case dhcpIPaddrLeaseTime :
+ opt_len = _dhcpUdpSocket.read();
+ _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
+ _dhcpLeaseTime = ntohl(_dhcpLeaseTime);
+ _renewInSec = _dhcpLeaseTime;
+ break;
+
default :
opt_len = _dhcpUdpSocket.read();
// Skip over the rest of this option
@@ -322,6 +380,68 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
return type;
}
+
+/*
+ returns:
+ 0/DHCP_CHECK_NONE: nothing happened
+ 1/DHCP_CHECK_RENEW_FAIL: renew failed
+ 2/DHCP_CHECK_RENEW_OK: renew success
+ 3/DHCP_CHECK_REBIND_FAIL: rebind fail
+ 4/DHCP_CHECK_REBIND_OK: rebind success
+*/
+int DhcpClass::checkLease(){
+ //this uses a signed / unsigned trick to deal with millis overflow
+ unsigned long now = millis();
+ signed long snow = (long)now;
+ int rc=DHCP_CHECK_NONE;
+ if (_lastCheck != 0){
+ signed long factor;
+ //calc how many ms past the timeout we are
+ factor = snow - (long)_secTimeout;
+ //if on or passed the timeout, reduce the counters
+ if ( factor >= 0 ){
+ //next timeout should be now plus 1000 ms minus parts of second in factor
+ _secTimeout = snow + 1000 - factor % 1000;
+ //how many seconds late are we, minimum 1
+ factor = factor / 1000 +1;
+
+ //reduce the counters by that mouch
+ //if we can assume that the cycle time (factor) is fairly constant
+ //and if the remainder is less than cycle time * 2
+ //do it early instead of late
+ if(_renewInSec < factor*2 )
+ _renewInSec = 0;
+ else
+ _renewInSec -= factor;
+
+ if(_rebindInSec < factor*2 )
+ _rebindInSec = 0;
+ else
+ _rebindInSec -= factor;
+ }
+
+ //if we have a lease but should renew, do it
+ if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
+ _dhcp_state = STATE_DHCP_REREQUEST;
+ rc = 1 + request_DHCP_lease();
+ }
+
+ //if we have a lease or is renewing but should bind, do it
+ if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
+ //this should basically restart completely
+ _dhcp_state = STATE_DHCP_START;
+ reset_DHCP_lease();
+ rc = 3 + request_DHCP_lease();
+ }
+ }
+ else{
+ _secTimeout = snow + 1000;
+ }
+
+ _lastCheck = now;
+ return rc;
+}
+
IPAddress DhcpClass::getLocalIp()
{
return IPAddress(_dhcpLocalIp);
diff --git a/libraries/Ethernet/Dhcp.h b/libraries/Ethernet/Dhcp.h
index 149876d..4a47936 100755
--- a/libraries/Ethernet/Dhcp.h
+++ b/libraries/Ethernet/Dhcp.h
@@ -45,6 +45,13 @@
#define MAX_DHCP_OPT 16
#define HOST_NAME "WIZnet"
+#define DEFAULT_LEASE (900) //default lease time in seconds
+
+#define DHCP_CHECK_NONE (0)
+#define DHCP_CHECK_RENEW_FAIL (1)
+#define DHCP_CHECK_RENEW_OK (2)
+#define DHCP_CHECK_REBIND_FAIL (3)
+#define DHCP_CHECK_REBIND_OK (4)
enum
{
@@ -139,8 +146,19 @@ private:
uint8_t _dhcpGatewayIp[4];
uint8_t _dhcpDhcpServerIp[4];
uint8_t _dhcpDnsServerIp[4];
+ uint32_t _dhcpLeaseTime;
+ uint32_t _dhcpT1, _dhcpT2;
+ signed long _renewInSec;
+ signed long _rebindInSec;
+ signed long _lastCheck;
+ unsigned long _timeout;
+ unsigned long _responseTimeout;
+ unsigned long _secTimeout;
+ uint8_t _dhcp_state;
EthernetUDP _dhcpUdpSocket;
+ int request_DHCP_lease();
+ void reset_DHCP_lease();
void presend_DHCP();
void send_DHCP_MESSAGE(uint8_t, uint16_t);
void printByte(char *, uint8_t);
@@ -154,6 +172,7 @@ public:
IPAddress getDnsServerIp();
int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
+ int checkLease();
};
#endif
diff --git a/libraries/Ethernet/Ethernet.cpp b/libraries/Ethernet/Ethernet.cpp
index c298f3d..5d28f71 100644
--- a/libraries/Ethernet/Ethernet.cpp
+++ b/libraries/Ethernet/Ethernet.cpp
@@ -10,7 +10,8 @@ uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {
int EthernetClass::begin(uint8_t *mac_address)
{
- DhcpClass dhcp;
+ _dhcp = new DhcpClass();
+
// Initialise the basic info
W5100.init();
@@ -18,15 +19,15 @@ int EthernetClass::begin(uint8_t *mac_address)
W5100.setIPAddress(IPAddress(0,0,0,0).raw_address());
// Now try to get our config info from a DHCP server
- int ret = dhcp.beginWithDHCP(mac_address);
+ int ret = _dhcp->beginWithDHCP(mac_address);
if(ret == 1)
{
// We've successfully found a DHCP server and got our configuration info, so set things
// accordingly
- W5100.setIPAddress(dhcp.getLocalIp().raw_address());
- W5100.setGatewayIp(dhcp.getGatewayIp().raw_address());
- W5100.setSubnetMask(dhcp.getSubnetMask().raw_address());
- _dnsServerAddress = dhcp.getDnsServerIp();
+ W5100.setIPAddress(_dhcp->getLocalIp().raw_address());
+ W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address());
+ W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address());
+ _dnsServerAddress = _dhcp->getDnsServerIp();
}
return ret;
@@ -66,6 +67,31 @@ void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server
_dnsServerAddress = dns_server;
}
+int EthernetClass::maintain(){
+ int rc = DHCP_CHECK_NONE;
+ if(_dhcp != NULL){
+ //we have a pointer to dhcp, use it
+ rc = _dhcp->checkLease();
+ switch ( rc ){
+ case DHCP_CHECK_NONE:
+ //nothing done
+ break;
+ case DHCP_CHECK_RENEW_OK:
+ case DHCP_CHECK_REBIND_OK:
+ //we might have got a new IP.
+ W5100.setIPAddress(_dhcp->getLocalIp().raw_address());
+ W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address());
+ W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address());
+ _dnsServerAddress = _dhcp->getDnsServerIp();
+ break;
+ default:
+ //this is actually a error, it will retry though
+ break;
+ }
+ }
+ return rc;
+}
+
IPAddress EthernetClass::localIP()
{
IPAddress ret;
diff --git a/libraries/Ethernet/Ethernet.h b/libraries/Ethernet/Ethernet.h
index c916dda..2a07ff3 100644
--- a/libraries/Ethernet/Ethernet.h
+++ b/libraries/Ethernet/Ethernet.h
@@ -6,12 +6,14 @@
#include "IPAddress.h"
#include "EthernetClient.h"
#include "EthernetServer.h"
+#include "Dhcp.h"
#define MAX_SOCK_NUM 4
class EthernetClass {
private:
IPAddress _dnsServerAddress;
+ DhcpClass* _dhcp;
public:
static uint8_t _state[MAX_SOCK_NUM];
static uint16_t _server_port[MAX_SOCK_NUM];
@@ -23,6 +25,7 @@ public:
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server);
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway);
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet);
+ int maintain();
IPAddress localIP();
IPAddress subnetMask();
diff --git a/libraries/Ethernet/EthernetClient.cpp b/libraries/Ethernet/EthernetClient.cpp
index a77a62b..9885efb 100644
--- a/libraries/Ethernet/EthernetClient.cpp
+++ b/libraries/Ethernet/EthernetClient.cpp
@@ -41,7 +41,7 @@ int EthernetClient::connect(IPAddress ip, uint16_t port) {
for (int i = 0; i < MAX_SOCK_NUM; i++) {
uint8_t s = W5100.readSnSR(i);
- if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
+ if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {
_sock = i;
break;
}
diff --git a/libraries/Ethernet/EthernetUdp.cpp b/libraries/Ethernet/EthernetUdp.cpp
index 9c752fc..3760052 100644
--- a/libraries/Ethernet/EthernetUdp.cpp
+++ b/libraries/Ethernet/EthernetUdp.cpp
@@ -52,15 +52,16 @@ uint8_t EthernetUDP::begin(uint16_t port) {
return 0;
_port = port;
+ _remaining = 0;
socket(_sock, SnMR::UDP, _port, 0);
return 1;
}
-/* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes.
- * returned value includes 8 byte UDP header!*/
+/* return number of bytes available in the current packet,
+ will return zero if parsePacket hasn't been called yet */
int EthernetUDP::available() {
- return W5100.getRXReceivedSize(_sock);
+ return _remaining;
}
/* Release any resources being used by this EthernetUDP instance */
@@ -116,11 +117,14 @@ size_t EthernetUDP::write(const uint8_t *buffer, size_t size)
int EthernetUDP::parsePacket()
{
- if (available() > 0)
+ // discard any remaining bytes in the last packet
+ flush();
+
+ if (W5100.getRXReceivedSize(_sock) > 0)
{
//HACK - hand-parse the UDP packet using TCP recv method
uint8_t tmpBuf[8];
- int ret =0;
+ int ret =0;
//read 8 header bytes and get IP and port from it
ret = recv(_sock,tmpBuf,8);
if (ret > 0)
@@ -128,8 +132,11 @@ int EthernetUDP::parsePacket()
_remoteIP = tmpBuf;
_remotePort = tmpBuf[4];
_remotePort = (_remotePort << 8) + tmpBuf[5];
+ _remaining = tmpBuf[6];
+ _remaining = (_remaining << 8) + tmpBuf[7];
+
// When we get here, any remaining bytes are the data
- ret = available();
+ ret = _remaining;
}
return ret;
}
@@ -140,34 +147,58 @@ int EthernetUDP::parsePacket()
int EthernetUDP::read()
{
uint8_t byte;
- if (recv(_sock, &byte, 1) > 0)
+
+ if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0))
{
// We read things without any problems
+ _remaining--;
return byte;
}
+
// If we get here, there's no data available
return -1;
}
int EthernetUDP::read(unsigned char* buffer, size_t len)
{
- /* In the readPacket that copes with truncating packets, the buffer was
- filled with this code. Not sure why it loops round reading out a byte
- at a time.
- int i;
- for(i=0;i<(int)bufLen;i++) {
- recv(_sock,tmpBuf,1);
- buf[i]=tmpBuf[0];
+
+ if (_remaining > 0)
+ {
+
+ int got;
+
+ if (_remaining <= len)
+ {
+ // data should fit in the buffer
+ got = recv(_sock, buffer, _remaining);
+ }
+ else
+ {
+ // too much data for the buffer,
+ // grab as much as will fit
+ got = recv(_sock, buffer, len);
+ }
+
+ if (got > 0)
+ {
+ _remaining -= got;
+ return got;
+ }
+
}
- */
- return recv(_sock, buffer, len);
+
+ // If we get here, there's no data available or recv failed
+ return -1;
+
}
int EthernetUDP::peek()
{
uint8_t b;
- // Unlike recv, peek doesn't check to see if there's any data available, so we must
- if (!available())
+ // Unlike recv, peek doesn't check to see if there's any data available, so we must.
+ // If the user hasn't called parsePacket yet then return nothing otherwise they
+ // may get the UDP header
+ if (!_remaining)
return -1;
::peek(_sock, &b);
return b;
@@ -175,7 +206,11 @@ int EthernetUDP::peek()
void EthernetUDP::flush()
{
- while (available())
+ // could this fail (loop endlessly) if _remaining > 0 and recv in read fails?
+ // should only occur if recv fails after telling us the data is there, lets
+ // hope the w5100 always behaves :)
+
+ while (_remaining)
{
read();
}
diff --git a/libraries/Ethernet/EthernetUdp.h b/libraries/Ethernet/EthernetUdp.h
index 9a2b653..8a6b7ab 100644
--- a/libraries/Ethernet/EthernetUdp.h
+++ b/libraries/Ethernet/EthernetUdp.h
@@ -48,6 +48,7 @@ private:
IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed
uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed
uint16_t _offset; // offset into the packet being sent
+ uint16_t _remaining; // remaining bytes of incoming packet yet to be processed
public:
EthernetUDP(); // Constructor
diff --git a/libraries/Ethernet/examples/ChatServer/ChatServer.ino b/libraries/Ethernet/examples/ChatServer/ChatServer.ino
index 9f819fd..de75257 100644
--- a/libraries/Ethernet/examples/ChatServer/ChatServer.ino
+++ b/libraries/Ethernet/examples/ChatServer/ChatServer.ino
@@ -12,7 +12,7 @@
created 18 Dec 2009
by David A. Mellis
- modified 10 August 2010
+ modified 12 March 2012
by Tom Igoe
*/
@@ -23,14 +23,16 @@
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network.
// gateway and subnet are optional:
-byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
+byte mac[] = {
+ 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1, 177);
IPAddress gateway(192,168,1, 1);
IPAddress subnet(255, 255, 0, 0);
+
// telnet defaults to port 23
EthernetServer server(23);
-boolean gotAMessage = false; // whether or not you got a message from the client yet
+boolean alreadyConnected = false; // whether or not the client was connected previously
void setup() {
// initialize the ethernet device
@@ -39,25 +41,34 @@ void setup() {
server.begin();
// open the serial port
Serial.begin(9600);
+ Serial.print("Chat server address:");
+ Serial.println(Ethernet.localIP());
}
void loop() {
// wait for a new client:
EthernetClient client = server.available();
-
+
// when the client sends the first byte, say hello:
if (client) {
- if (!gotAMessage) {
+ if (!alreadyConnected) {
+ // clead out the input buffer:
+ client.flush();
Serial.println("We have a new client");
client.println("Hello, client!");
- gotAMessage = true;
+ alreadyConnected = true;
+ }
+
+ if (client.available() > 0) {
+ // read the bytes incoming from the client:
+ char thisChar = client.read();
+ // echo the bytes back to the client:
+ server.write(thisChar);
+ // echo the bytes to the server as well:
+ Serial.write(thisChar);
}
-
- // read the bytes incoming from the client:
- char thisChar = client.read();
- // echo the bytes back to the client:
- server.write(thisChar);
- // echo the bytes to the server as well:
- Serial.print(thisChar);
}
}
+
+
+
diff --git a/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino b/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino
index a169443..4d4290d 100644
--- a/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino
+++ b/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino
@@ -6,15 +6,20 @@
the Adafruit Ethernet shield, either one will work, as long as it's got
a Wiznet Ethernet module on board.
+ This example has been updated to use version 2.0 of the Pachube.com API.
+ To make it work, create a feed with a datastream, and give it the ID
+ sensor1. Or change the code below to match your feed.
+
+
Circuit:
* Analog sensor attached to analog in 0
* Ethernet shield attached to pins 10, 11, 12, 13
created 15 March 2010
- updated 26 Oct 2011
- by Tom Igoe
+ updated 16 Mar 2012
+ by Tom Igoe with input from Usman Haque and Joe Saavedra
- http://www.tigoe.net/pcomp/code/category/arduinowiring/873
+http://arduino.cc/en/Tutorial/PachubeClient
This code is in the public domain.
*/
@@ -22,6 +27,10 @@
#include <SPI.h>
#include <Ethernet.h>
+#define APIKEY "YOUR API KEY GOES HERE" // replace your pachube api key here
+#define FEEDID 00000 // replace your feed ID
+#define USERAGENT "My Project" // user agent is the project name
+
// assign a MAC address for the ethernet controller.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
// fill in your address here:
@@ -34,26 +43,22 @@ IPAddress ip(10,0,1,20);
// initialize the library instance:
EthernetClient client;
-long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
-boolean lastConnected = false; // state of the connection last time through the main loop
-const int postingInterval = 10000; //delay between updates to Pachube.com
+// if you don't want to use DNS (and reduce your sketch size)
+// use the numeric IP instead of the name for the server:
+IPAddress server(216,52,233,122); // numeric IP for api.pachube.com
+//char server[] = "api.pachube.com"; // name address for pachube API
+
+unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
+boolean lastConnected = false; // state of the connection last time through the main loop
+const unsigned long postingInterval = 10*1000; //delay between updates to Pachube.com
void setup() {
// start serial port:
Serial.begin(9600);
- // start the Ethernet connection:
+ // start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
- // no point in carrying on, so do nothing forevermore:
- for(;;)
- ;
- }
- // give the ethernet module time to boot up:
- delay(1000);
- // start the Ethernet connection:
- if (Ethernet.begin(mac) == 0) {
- Serial.println("Failed to configure Ethernet using DHCP");
- // Configure manually:
+ // DHCP failed, so use a fixed IP address:
Ethernet.begin(mac, ip);
}
}
@@ -91,34 +96,43 @@ void loop() {
// this method makes a HTTP connection to the server:
void sendData(int thisData) {
// if there's a successful connection:
- if (client.connect("www.pachube.com", 80)) {
+ if (client.connect(server, 80)) {
Serial.println("connecting...");
- // send the HTTP PUT request.
- // fill in your feed address here:
- client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n");
- client.print("Host: www.pachube.com\n");
- // fill in your Pachube API key here:
- client.print("X-PachubeApiKey: YOUR_KEY_HERE\n");
+ // send the HTTP PUT request:
+ client.print("PUT /v2/feeds/");
+ client.print(FEEDID);
+ client.println(".csv HTTP/1.1");
+ client.println("Host: api.pachube.com");
+ client.print("X-PachubeApiKey: ");
+ client.println(APIKEY);
+ client.print("User-Agent: ");
+ client.println(USERAGENT);
client.print("Content-Length: ");
// calculate the length of the sensor reading in bytes:
- int thisLength = getLength(thisData);
- client.println(thisLength, DEC);
+ // 8 bytes for "sensor1," + number of digits of the data:
+ int thisLength = 8 + getLength(thisData);
+ client.println(thisLength);
// last pieces of the HTTP PUT request:
- client.print("Content-Type: text/csv\n");
- client.println("Connection: close\n");
+ client.println("Content-Type: text/csv");
+ client.println("Connection: close");
+ client.println();
// here's the actual content of the PUT request:
- client.println(thisData, DEC);
-
- // note the time that the connection was made:
- lastConnectionTime = millis();
+ client.print("sensor1,");
+ client.println(thisData);
+
}
else {
// if you couldn't make a connection:
Serial.println("connection failed");
+ Serial.println();
+ Serial.println("disconnecting.");
+ client.stop();
}
+ // note the time that the connection was made or attempted:
+ lastConnectionTime = millis();
}
diff --git a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino
index 4a03100..3535287 100644
--- a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino
+++ b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino
@@ -6,6 +6,10 @@
the Adafruit Ethernet shield, either one will work, as long as it's got
a Wiznet Ethernet module on board.
+ This example has been updated to use version 2.0 of the Pachube.com API.
+ To make it work, create a feed with two datastreams, and give them the IDs
+ sensor1 and sensor2. Or change the code below to match your feed.
+
This example uses the String library, which is part of the Arduino core from
version 0019.
@@ -14,9 +18,10 @@
* Ethernet shield attached to pins 10, 11, 12, 13
created 15 March 2010
- updated 26 Oct 2011
- by Tom Igoe
+ updated 16 Mar 2012
+ by Tom Igoe with input from Usman Haque and Joe Saavedra
+ http://arduino.cc/en/Tutorial/PachubeClientString
This code is in the public domain.
*/
@@ -24,9 +29,14 @@
#include <SPI.h>
#include <Ethernet.h>
+
+#define APIKEY "YOUR API KEY GOES HERE" // replace your pachube api key here
+#define FEEDID 00000 // replace your feed ID
+#define USERAGENT "My Project" // user agent is the project name
+
// assign a MAC address for the ethernet controller.
// fill in your address here:
-byte mac[] = {
+ byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// fill in an available IP address on your network here,
// for manual configuration:
@@ -35,9 +45,14 @@ IPAddress ip(10,0,1,20);
// initialize the library instance:
EthernetClient client;
-long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
-boolean lastConnected = false; // state of the connection last time through the main loop
-const int postingInterval = 10000; //delay between updates to Pachube.com
+// if you don't want to use DNS (and reduce your sketch size)
+// use the numeric IP instead of the name for the server:
+//IPAddress server(216,52,233,122); // numeric IP for api.pachube.com
+char server[] = "api.pachube.com"; // name address for pachube API
+
+unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
+boolean lastConnected = false; // state of the connection last time through the main loop
+const unsigned long postingInterval = 10*1000; //delay between updates to Pachube.com
void setup() {
// start serial port:
@@ -47,7 +62,7 @@ void setup() {
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
- // Configure manually:
+ // DHCP failed, so use a fixed IP address:
Ethernet.begin(mac, ip);
}
}
@@ -56,13 +71,15 @@ void loop() {
// read the analog sensor:
int sensorReading = analogRead(A0);
// convert the data to a String to send it:
- String dataString = String(sensorReading);
+
+ String dataString = "sensor1,";
+ dataString += sensorReading;
// you can append multiple readings to this String if your
// pachube feed is set up to handle multiple values:
int otherSensorReading = analogRead(A1);
- dataString += ",";
- dataString += String(otherSensorReading);
+ dataString += "\nsensor2,";
+ dataString += otherSensorReading;
// if there's incoming data from the net connection.
// send it out the serial port. This is for debugging
@@ -81,7 +98,7 @@ void loop() {
}
// if you're not connected, and ten seconds have passed since
- // your last connection, then connect again and send data:
+ // your last connection, then connect again and send data:
if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
sendData(dataString);
}
@@ -93,29 +110,36 @@ void loop() {
// this method makes a HTTP connection to the server:
void sendData(String thisData) {
// if there's a successful connection:
- if (client.connect("www.pachube.com", 80)) {
+ if (client.connect(server, 80)) {
Serial.println("connecting...");
- // send the HTTP PUT request.
- // fill in your feed address here:
- client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n");
- client.print("Host: www.pachube.com\n");
- // fill in your Pachube API key here:
- client.print("X-PachubeApiKey: YOUR_KEY_HERE\n");
+ // send the HTTP PUT request:
+ client.print("PUT /v2/feeds/");
+ client.print(FEEDID);
+ client.println(".csv HTTP/1.1");
+ client.println("Host: api.pachube.com");
+ client.print("X-PachubeApiKey: ");
+ client.println(APIKEY);
+ client.print("User-Agent: ");
+ client.println(USERAGENT);
client.print("Content-Length: ");
- client.println(thisData.length(), DEC);
+ client.println(thisData.length());
// last pieces of the HTTP PUT request:
- client.print("Content-Type: text/csv\n");
- client.println("Connection: close\n");
+ client.println("Content-Type: text/csv");
+ client.println("Connection: close");
+ client.println();
// here's the actual content of the PUT request:
client.println(thisData);
-
- // note the time that the connection was made:
- lastConnectionTime = millis();
}
else {
// if you couldn't make a connection:
Serial.println("connection failed");
+ Serial.println();
+ Serial.println("disconnecting.");
+ client.stop();
}
+ // note the time that the connection was made or attempted:
+ lastConnectionTime = millis();
}
+
diff --git a/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino b/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino
index f113e17..a3b397d 100644
--- a/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino
+++ b/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino
@@ -14,7 +14,7 @@
version 0019.
Circuit:
- * Ethernet shield attached to pins 10, 11, 12, 13
+ * Ethernet shield attached to pins 10, 11, 12, 13
created 21 May 2011
by Tom Igoe
@@ -35,12 +35,12 @@ IPAddress ip(192,168,1,20);
// initialize the library instance:
EthernetClient client;
-const int requestInterval = 60000; // delay between requests
+const unsigned long requestInterval = 60000; // delay between requests
char serverName[] = "api.twitter.com"; // twitter URL
boolean requested; // whether you've made a request since connecting
-long lastAttemptTime = 0; // last time you connected to the server, in milliseconds
+unsigned long lastAttemptTime = 0; // last time you connected to the server, in milliseconds
String currentLine = ""; // string to hold the text from server
String tweet = ""; // string to hold the tweet
@@ -51,13 +51,17 @@ void setup() {
currentLine.reserve(256);
tweet.reserve(150);
-// initialize serial:
+ // initialize serial:
Serial.begin(9600);
// attempt a DHCP connection:
+ Serial.println("Attempting to get an IP address using DHCP:");
if (!Ethernet.begin(mac)) {
// if DHCP fails, start with a hard-coded address:
+ Serial.println("failed to get an IP address using DHCP, trying manually");
Ethernet.begin(mac, ip);
}
+ Serial.print("My address:");
+ Serial.println(Ethernet.localIP());
// connect to Twitter:
connectToServer();
}
@@ -114,7 +118,7 @@ void connectToServer() {
Serial.println("connecting to server...");
if (client.connect(serverName, 80)) {
Serial.println("making HTTP request...");
- // make HTTP GET request to twitter:
+ // make HTTP GET request to twitter:
client.println("GET /1/statuses/user_timeline.xml?screen_name=arduino&count=1 HTTP/1.1");
client.println("HOST: api.twitter.com");
client.println();
@@ -122,3 +126,4 @@ void connectToServer() {
// note the time of this connect attempt:
lastAttemptTime = millis();
}
+
diff --git a/libraries/Ethernet/examples/WebServer/WebServer.ino b/libraries/Ethernet/examples/WebServer/WebServer.ino
index 6837f83..7cf2c53 100644
--- a/libraries/Ethernet/examples/WebServer/WebServer.ino
+++ b/libraries/Ethernet/examples/WebServer/WebServer.ino
@@ -10,7 +10,7 @@
created 18 Dec 2009
by David A. Mellis
- modified 4 Sep 2010
+ modified 20 Mar 2012
by Tom Igoe
*/
@@ -20,7 +20,8 @@
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
-byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
+byte mac[] = {
+ 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1, 177);
// Initialize the Ethernet server library
@@ -28,23 +29,27 @@ IPAddress ip(192,168,1, 177);
// (port 80 is default for HTTP):
EthernetServer server(80);
-void setup()
-{
+void setup() {
+ Serial.begin(9600);
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
+ Serial.print("server is at ");
+ Serial.println(Ethernet.localIP());
}
-void loop()
-{
+
+void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
+ Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
+ Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
@@ -52,16 +57,22 @@ void loop()
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
+ client.println("Connnection: close");
client.println();
-
+ client.println("<!DOCTYPE HTML>");
+ client.println("<html>");
+ // add a meta refresh tag, so the browser pulls again every 5 seconds:
+ client.println("<meta http-equiv=\"refresh\" content=\"5\">");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
+ int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
- client.print(analogRead(analogChannel));
- client.println("<br />");
+ client.print(sensorReading);
+ client.println("<br />");
}
+ client.println("</html>");
break;
}
if (c == '\n') {
@@ -78,5 +89,7 @@ void loop()
delay(1);
// close the connection:
client.stop();
+ Serial.println("client disonnected");
}
}
+
diff --git a/libraries/SD/utility/SdFatUtil.h b/libraries/SD/utility/SdFatUtil.h
index 283fcb2..7d6b410 100644
--- a/libraries/SD/utility/SdFatUtil.h
+++ b/libraries/SD/utility/SdFatUtil.h
@@ -56,7 +56,7 @@ static UNUSEDOK int FreeRam(void) {
* \param[in] str Pointer to string stored in flash memory.
*/
static NOINLINE void SerialPrint_P(PGM_P str) {
- for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c);
+ for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
}
//------------------------------------------------------------------------------
/**
diff --git a/libraries/Servo/Servo.cpp b/libraries/Servo/Servo.cpp
index acac29a..a716433 100755
--- a/libraries/Servo/Servo.cpp
+++ b/libraries/Servo/Servo.cpp
@@ -89,7 +89,7 @@ static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t
}
else {
// finished all channels so wait for the refresh period to expire before starting over
- if( (unsigned)*TCNTn < (usToTicks(REFRESH_INTERVAL) + 4) ) // allow a few ticks to ensure the next OCR1A not missed
+ if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
else
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
@@ -298,7 +298,7 @@ void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
- if( (channel >= 0) && (channel < MAX_SERVOS) ) // ensure channel is valid
+ if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if( value < SERVO_MIN() ) // ensure pulse width is valid
value = SERVO_MIN();
diff --git a/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino b/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino
index 1f535bd..615d2b3 100644
--- a/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino
+++ b/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino
@@ -1,6 +1,23 @@
+/*
+ Software serial multple serial test
+
+ Receives from the hardware serial, sends to software serial.
+ Receives from software serial, sends to hardware serial.
+
+ The circuit:
+ * RX is digital pin 2 (connect to TX of other device)
+ * TX is digital pin 3 (connect to RX of other device)
+
+ created back in the mists of time
+ by Tom Igoe
+ based on Mikal Hart's example
+
+ This example code is in the public domain.
+
+ */
#include <SoftwareSerial.h>
-SoftwareSerial mySerial(2, 3);
+SoftwareSerial mySerial(2, 3); // RX, TX
void setup()
{
diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp
index d83f478..4e7a17c 100755
--- a/libraries/Wire/Wire.cpp
+++ b/libraries/Wire/Wire.cpp
@@ -15,6 +15,8 @@
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" {
@@ -73,14 +75,14 @@ void TwoWire::begin(int address)
begin((uint8_t)address);
}
-uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
+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);
+ uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;
@@ -88,9 +90,19 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
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);
+ 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)
@@ -109,10 +121,23 @@ void TwoWire::beginTransmission(int address)
beginTransmission((uint8_t)address);
}
-uint8_t TwoWire::endTransmission(void)
+//
+// 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);
+ int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
@@ -121,6 +146,14 @@ uint8_t TwoWire::endTransmission(void)
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)
diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h
index 9ea4afd..a93d0f5 100755
--- a/libraries/Wire/Wire.h
+++ b/libraries/Wire/Wire.h
@@ -15,6 +15,8 @@
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
@@ -50,8 +52,11 @@ class TwoWire : public Stream
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);
diff --git a/libraries/Wire/utility/twi.c b/libraries/Wire/utility/twi.c
index d80114b..6b2db3c 100644
--- a/libraries/Wire/utility/twi.c
+++ b/libraries/Wire/utility/twi.c
@@ -15,6 +15,8 @@
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>
@@ -37,14 +39,16 @@
#include "twi.h"
static volatile uint8_t twi_state;
-static uint8_t twi_slarw;
+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 uint8_t twi_masterBufferLength;
+static volatile uint8_t twi_masterBufferLength;
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_txBufferIndex;
@@ -65,6 +69,8 @@ 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);
@@ -103,9 +109,10 @@ void twi_setAddress(uint8_t address)
* 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 twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
{
uint8_t i;
@@ -119,6 +126,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
continue;
}
twi_state = TWI_MRX;
+ twi_sendStop = sendStop;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
@@ -135,8 +143,20 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
twi_slarw = TW_READ;
twi_slarw |= address << 1;
- // send start condition
- TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+ 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){
@@ -162,13 +182,14 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
* 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 twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
{
uint8_t i;
@@ -182,6 +203,7 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
continue;
}
twi_state = TWI_MTX;
+ twi_sendStop = sendStop;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
@@ -198,8 +220,23 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
twi_slarw = TW_WRITE;
twi_slarw |= address << 1;
- // send start condition
- TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+ // 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)){
@@ -343,7 +380,16 @@ SIGNAL(TWI_vect)
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
twi_reply(1);
}else{
- twi_stop();
+ 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
@@ -374,6 +420,17 @@ SIGNAL(TWI_vect)
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;
diff --git a/libraries/Wire/utility/twi.h b/libraries/Wire/utility/twi.h
index 831b928..6526593 100755
--- a/libraries/Wire/utility/twi.h
+++ b/libraries/Wire/utility/twi.h
@@ -40,8 +40,8 @@
void twi_init(void);
void twi_setAddress(uint8_t);
- uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t);
- uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, 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) );