Skip to content

Non-blocking TCP connect; some edits for Arduino 1.5; a fix for duplicate packet spam #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 53 additions & 27 deletions UIPClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions UIPClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions UIPEthernet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@

#include <Arduino.h>
#include "UIPEthernet.h"
#include "Enc28J60Network.h"
#include "utility/Enc28J60Network.h"

#if(defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM)
#include "HardwareSerial.h"
#endif

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"
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion UIPServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
8 changes: 4 additions & 4 deletions UIPUdp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
167 changes: 167 additions & 0 deletions examples/TcpClientNonBlocking/TcpClientNonBlocking.ino
Original file line number Diff line number Diff line change
@@ -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 <UIPEthernet.h>

#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;
}
10 changes: 10 additions & 0 deletions library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name=uIP
author=
email=
sentence=
paragraph=
url=
architectures=avr
version=1.0
dependencies=
core-dependencies=arduino (>=1.5.0)