diff options
author | Cristian Maglie <c.maglie@bug.st> | 2012-05-21 01:56:06 +0200 |
---|---|---|
committer | Cristian Maglie <c.maglie@bug.st> | 2012-05-22 11:23:47 +0200 |
commit | 3786e337e0211ca1ef94b37b03e891adfb3b5f9a (patch) | |
tree | dd7f8f6fd396243460ec22da89bfbd71d552f484 /libraries | |
parent | 324023a67afd1691f12ead4388d7cdf1a9d1a6ef (diff) | |
parent | 9a8976ce56bcdb70815dd58c1764d9e5c3b6fe95 (diff) |
Pre-merge upstream Arduino
Diffstat (limited to 'libraries')
-rwxr-xr-x | libraries/Ethernet/Dhcp.cpp | 158 | ||||
-rwxr-xr-x | libraries/Ethernet/Dhcp.h | 19 | ||||
-rw-r--r-- | libraries/Ethernet/Ethernet.cpp | 38 | ||||
-rw-r--r-- | libraries/Ethernet/Ethernet.h | 3 | ||||
-rw-r--r-- | libraries/Ethernet/EthernetClient.cpp | 2 | ||||
-rw-r--r-- | libraries/Ethernet/EthernetUdp.cpp | 73 | ||||
-rw-r--r-- | libraries/Ethernet/EthernetUdp.h | 1 | ||||
-rw-r--r-- | libraries/Ethernet/examples/ChatServer/ChatServer.ino | 37 | ||||
-rw-r--r-- | libraries/Ethernet/examples/PachubeClient/PachubeClient.ino | 78 | ||||
-rw-r--r-- | libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino | 72 | ||||
-rw-r--r-- | libraries/Ethernet/examples/TwitterClient/TwitterClient.ino | 15 | ||||
-rw-r--r-- | libraries/Ethernet/examples/WebServer/WebServer.ino | 31 | ||||
-rw-r--r-- | libraries/SD/utility/SdFatUtil.h | 2 | ||||
-rwxr-xr-x | libraries/Servo/Servo.cpp | 4 | ||||
-rw-r--r-- | libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino | 19 | ||||
-rwxr-xr-x | libraries/Wire/Wire.cpp | 43 | ||||
-rwxr-xr-x | libraries/Wire/Wire.h | 5 | ||||
-rw-r--r-- | libraries/Wire/utility/twi.c | 75 | ||||
-rwxr-xr-x | libraries/Wire/utility/twi.h | 4 |
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) ); |