diff --git a/UIPClient.cpp b/UIPClient.cpp index 452f989..4abd265 100644 --- a/UIPClient.cpp +++ b/UIPClient.cpp @@ -19,14 +19,14 @@ extern "C" { -#import "uip-conf.h" -#import "uip.h" -#import "uip_arp.h" +#import "utility/uip-conf.h" +#import "utility/uip.h" +#import "utility/uip_arp.h" #import "string.h" } #include "UIPEthernet.h" #include "UIPClient.h" -#include "Dns.h" +#include "utility/Dns.h" #ifdef UIPETHERNET_DEBUG_CLIENT #include "HardwareSerial.h" @@ -55,34 +55,60 @@ UIPClient::UIPClient(uip_userdata_closed_t* conn_data) : { } -int -UIPClient::connect(IPAddress ip, uint16_t port) +uip_tcpstate_t UIPClient::connectTick() { - uip_ipaddr_t ipaddr; - uip_ip_addr(ipaddr, ip); - _uip_conn = uip_connect(&ipaddr, htons(port)); - if (_uip_conn) - { - while((_uip_conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) - { - UIPEthernet.tick(); - if ((_uip_conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) - { + if((_uip_conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) + { + UIPEthernet.tick(); + if ((_uip_conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) + { #ifdef UIPETHERNET_DEBUG_CLIENT - Serial.print("connected, state: "); - Serial.print(((uip_userdata_t *)_uip_conn->appstate.user)->state); - Serial.print(", first packet in: "); - Serial.println(((uip_userdata_t *)_uip_conn->appstate.user)->packets_in[0]); + Serial.print("connected, state: "); + Serial.print(((uip_userdata_t *)_uip_conn->appstate.user)->state); + Serial.print(", first packet in: "); + Serial.println(((uip_userdata_t *)_uip_conn->appstate.user)->packets_in[0]); #endif - return 1; - } - } - } - return 0; + return UIP_TCP_CONNECTED; + } + return UIP_TCP_CONNECTING; + } + return UIP_TCP_FAILED; +} + +int UIPClient::connect(IPAddress ip, uint16_t port) +{ + return connect(ip, port, false); +} + +int +UIPClient::connect(IPAddress ip, uint16_t port, bool noBlock) +{ + uip_ipaddr_t ipaddr; + uip_ip_addr(ipaddr, ip); + _uip_conn = uip_connect(&ipaddr, htons(port)); + + if(!_uip_conn) + return 0; + else if(noBlock) + { + // Does this need a tick right here? + return 1; + } + + uip_tcpstate_t state; + while((state = connectTick()) != UIP_TCP_FAILED); + if(state != UIP_TCP_FAILED) + return 1; + return 0; +} + +int UIPClient::connect(const char *host, uint16_t port) +{ + return connect(host, port, false); } int -UIPClient::connect(const char *host, uint16_t port) +UIPClient::connect(const char *host, uint16_t port, bool noBlock) { // Look up the host first int ret = 0; @@ -93,7 +119,7 @@ UIPClient::connect(const char *host, uint16_t port) dns.begin(UIPEthernet.dnsServerIP()); ret = dns.getHostByName(host, remote_addr); if (ret == 1) { - return connect(remote_addr, port); + return connect(remote_addr, port, noBlock); } #endif return ret; diff --git a/UIPClient.h b/UIPClient.h index cae8f97..8ccc390 100644 --- a/UIPClient.h +++ b/UIPClient.h @@ -38,6 +38,13 @@ extern "C" { #define UIP_CLIENT_CLOSED 2 #define UIP_CLIENT_RESTART 4 +typedef enum +{ + UIP_TCP_FAILED, + UIP_TCP_CONNECTING, + UIP_TCP_CONNECTED +} uip_tcpstate_t; + typedef uint8_t uip_socket_ptr; typedef struct { @@ -57,6 +64,11 @@ class UIPClient : public Client { public: UIPClient(); + + uip_tcpstate_t connectTick(); + int connect(IPAddress ip, uint16_t port, bool noBlock); + int connect(const char *host, uint16_t port, bool noBlock); + int connect(IPAddress ip, uint16_t port); int connect(const char *host, uint16_t port); int read(uint8_t *buf, size_t size); diff --git a/UIPEthernet.cpp b/UIPEthernet.cpp index fee72f0..bff7ac4 100644 --- a/UIPEthernet.cpp +++ b/UIPEthernet.cpp @@ -19,7 +19,7 @@ #include #include "UIPEthernet.h" -#include "Enc28J60Network.h" +#include "utility/Enc28J60Network.h" #if(defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM) #include "HardwareSerial.h" @@ -27,7 +27,7 @@ extern "C" { -#include "uip-conf.h" +#include "utility/uip-conf.h" #include "utility/uip.h" #include "utility/uip_arp.h" #include "utility/uip_timer.h" @@ -213,7 +213,7 @@ UIPEthernetClass::tick() if (uip_timer_expired(&periodic_timer)) { - uip_timer_reset(&periodic_timer); + uip_timer_restart(&periodic_timer); for (int i = 0; i < UIP_CONNS; i++) { uip_periodic(i); diff --git a/UIPServer.cpp b/UIPServer.cpp index 239c20c..07ae0e2 100644 --- a/UIPServer.cpp +++ b/UIPServer.cpp @@ -19,7 +19,7 @@ #include "UIPEthernet.h" #include "UIPServer.h" extern "C" { - #include "uip-conf.h" + #include "utility/uip-conf.h" } UIPServer::UIPServer(uint16_t port) : _port(htons(port)) diff --git a/UIPUdp.cpp b/UIPUdp.cpp index 6b5dbf6..122d403 100644 --- a/UIPUdp.cpp +++ b/UIPUdp.cpp @@ -19,16 +19,16 @@ #include "UIPEthernet.h" #include "UIPUdp.h" -#include "Dns.h" +#include "utility/Dns.h" #ifdef UIPETHERNET_DEBUG_UDP #include "HardwareSerial.h" #endif extern "C" { -#include "uip-conf.h" -#include "uip.h" -#include "uip_arp.h" +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" } #if UIP_UDP diff --git a/examples/TcpClientNonBlocking/TcpClientNonBlocking.ino b/examples/TcpClientNonBlocking/TcpClientNonBlocking.ino new file mode 100644 index 0000000..4c53dd3 --- /dev/null +++ b/examples/TcpClientNonBlocking/TcpClientNonBlocking.ino @@ -0,0 +1,167 @@ +// This example shows the use of non-blocking connect. +// DNS lookup (if you use a hostname instead of an IP) is still blocking, though. + +// Every 5 seconds a HTTP request is sent to 192.168.1.1 +// Reply data is sent out via serial + +// The LED flash speed indicates the connection state: +// Fast = Connecting +// Medium = HTTP request sent, waiting for reply +// Slow = Got reply, now idle + +#include + +#define CONNSTATE_IDLE 0 +#define CONNSTATE_CONNECTING 1 +#define CONNSTATE_DATASENT 2 + +#define LED_PIN 3 + +typedef unsigned long millis_t; + +static EthernetClient client; +static byte flashSpeed; + +void setup() +{ + Serial.begin(115200); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + Ethernet.begin(mac); + + Serial.print(F("IP: ")); + Serial.println(Ethernet.localIP()); + Serial.print(F("Subnet: ")); + Serial.println(Ethernet.subnetMask()); + Serial.print(F("Gateway: ")); + Serial.println(Ethernet.gatewayIP()); + Serial.print(F("DNS: ")); + Serial.println(Ethernet.dnsServerIP()); + + flashSpeed = 200; + + pinMode(LED_PIN, OUTPUT); +} + +void loop() +{ + net(); + flashLED(); +} + +static void flashLED() +{ + static millis_t lastFlash; + static byte ledState = LOW; + + millis_t now = millis(); + if(now - lastFlash > flashSpeed) + { + lastFlash = now; + digitalWrite(LED_PIN, ledState); + ledState = !ledState; + } +} + +static void net() +{ + static millis_t lastRequest; + static millis_t requestStart; + static byte connState = CONNSTATE_IDLE; + + switch(connState) + { + case CONNSTATE_IDLE: + { + millis_t now = millis(); + if(now - lastRequest > 5000) // Send a request every 5 seconds + { + lastRequest = now; + if(net_connect()) + { + requestStart = millis(); + connState = CONNSTATE_CONNECTING; + flashSpeed = 30; // Fast flash when connecting + } + } + } + break; + case CONNSTATE_CONNECTING: + connState = net_send(); + if(connState == CONNSTATE_DATASENT) + flashSpeed = 100; // Medium flash when data sent and waiting for a reply + else if(connState == CONNSTATE_IDLE) + flashSpeed = 200; // Gone back to idle, must have failed to connect + break; + case CONNSTATE_DATASENT: + if(net_getData()) + { + connState = CONNSTATE_IDLE; + flashSpeed = 200; // Slow flash when request complete + + // Request time + Serial.println(); + Serial.println(); + Serial.print(F("Request time: ")); + Serial.println(millis() - requestStart); + } + break; + default: + break; + } +} + +// Start connecting +static bool net_connect() +{ + Serial.println(F("Connecting")); + return client.connect(IPAddress(192,168,1,1), 80, true); +} + +static byte net_send() +{ + uip_tcpstate_t state = client.connectTick(); // Update connection status etc + if(state == UIP_TCP_FAILED) // Failed to connect (timed out or something) + { + Serial.println(F("Connection failed")); + return CONNSTATE_IDLE; + } + else if(state == UIP_TCP_CONNECTED) // Connection established, send some data + { + Serial.println(F("Connected, sending request")); + + client.println(F("GET /index.html HTTP/1.1")); + client.println(F("Host: 192.168.1.1")); + client.println(F("Connection: Close")); + client.println(); + + Serial.println(F("Request sent")); + + return CONNSTATE_DATASENT; + } + + // Still connecting... + return CONNSTATE_CONNECTING; +} + +static bool net_getData() +{ + // See if data is available + if(!client.available()) + return false; + + // Get and show data + int size; + while((size = client.available()) > 0) + { + byte* msg = (byte*)malloc(size); + size = client.read(msg, size); + Serial.write(msg, size); + free(msg); + } + + // Close connection + client.stop(); + + return true; +} \ No newline at end of file diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..3487f7f --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=uIP +author= +email= +sentence= +paragraph= +url= +architectures=avr +version=1.0 +dependencies= +core-dependencies=arduino (>=1.5.0)