Skip to content

Commit 2ac4e2f

Browse files
committed
Imported work from DavyLandman/NBEthernet adding a non blocking variant of most Ethernet functions.
Non blocking alternatives added for: - Dhcp::* - Dns::getHostbyName - Ethernet::begin (DHCP version) - Ethernet::maintain - EthernetClient::connect(*)
1 parent a2ca62d commit 2ac4e2f

File tree

8 files changed

+395
-159
lines changed

8 files changed

+395
-159
lines changed

libraries/Ethernet/Dhcp.cpp

+110-86
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,18 @@
99
#include "Arduino.h"
1010
#include "util.h"
1111

12+
1213
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
1314
{
15+
initialize(mac, timeout, responseTimeout);
16+
int result = 0;
17+
while (result == 0) {
18+
result = successful();
19+
}
20+
return _dhcp_state;
21+
}
22+
23+
void DhcpClass::initialize(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) {
1424
_dhcpLeaseTime=0;
1525
_dhcpT1=0;
1626
_dhcpT2=0;
@@ -24,107 +34,127 @@ int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long
2434

2535
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
2636
_dhcp_state = STATE_DHCP_START;
27-
return request_DHCP_lease();
37+
init_new_DHCP_request();
2838
}
2939

3040
void DhcpClass::reset_DHCP_lease(){
3141
// zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
3242
memset(_dhcpLocalIp, 0, 20);
3343
}
3444

35-
//return:0 on error, 1 if request is sent and response is received
36-
int DhcpClass::request_DHCP_lease(){
37-
38-
uint8_t messageType = 0;
39-
40-
45+
// 0 = not finished, 1 = finished and successful, 2 = finished but failed
46+
int DhcpClass::successful() {
47+
int result = step_DHCP_lease();
48+
if ((millis() - _startTime) > _timeout) {
49+
result = 2;
50+
_dhcp_state = STATE_DHCP_TIMEOUT;
51+
}
52+
if (result > 0) {
53+
_dhcpUdpSocket.stop();
54+
_dhcpTransactionId++;
55+
}
56+
return result;
57+
}
4158

59+
void DhcpClass::init_new_DHCP_request(){
4260
// Pick an initial transaction ID
4361
_dhcpTransactionId = random(1UL, 2000UL);
4462
_dhcpInitialTransactionId = _dhcpTransactionId;
4563

46-
_dhcpUdpSocket.stop();
4764
if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
4865
{
49-
// Couldn't get a socket
50-
return 0;
66+
_dhcp_state = STATE_DHCP_CONNECTION_FAILED;
5167
}
68+
_startTime = millis();
69+
}
70+
71+
//return:0 on error, 1 if request is sent and response is received
72+
int DhcpClass::request_DHCP_lease(){
73+
init_new_DHCP_request();
5274

5375
presend_DHCP();
5476

5577
int result = 0;
78+
do {
79+
result = step_DHCP_lease();
80+
} while(result == 0 && ((millis() - _startTime) > _timeout));
81+
82+
_dhcpUdpSocket.stop();
83+
_dhcpTransactionId++;
84+
85+
return result == 1;
86+
}
87+
88+
int DhcpClass::step_DHCP_lease(){
89+
int result = 0;
90+
uint8_t messageType = 0;
91+
92+
if (_dhcp_state == STATE_DHCP_CONNECTION_FAILED) {
93+
return 2;
94+
}
95+
if (_dhcp_state == STATE_DHCP_LEASED) {
96+
return 1;
97+
}
5698

57-
unsigned long startTime = millis();
99+
if(_dhcp_state == STATE_DHCP_START)
100+
{
101+
_dhcpTransactionId++;
58102

59-
while(_dhcp_state != STATE_DHCP_LEASED)
103+
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - _startTime) / 1000));
104+
_startResponseTime = millis();
105+
_dhcp_state = STATE_DHCP_DISCOVER;
106+
}
107+
else if(_dhcp_state == STATE_DHCP_REREQUEST){
108+
_dhcpTransactionId++;
109+
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - _startTime)/1000));
110+
_startResponseTime = millis();
111+
_dhcp_state = STATE_DHCP_REQUEST;
112+
}
113+
else if(_dhcp_state == STATE_DHCP_DISCOVER)
60114
{
61-
if(_dhcp_state == STATE_DHCP_START)
115+
uint32_t respId;
116+
messageType = tryParseDHCPResponse(respId);
117+
if(messageType == DHCP_OFFER)
62118
{
63-
_dhcpTransactionId++;
64-
65-
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
66-
_dhcp_state = STATE_DHCP_DISCOVER;
67-
}
68-
else if(_dhcp_state == STATE_DHCP_REREQUEST){
69-
_dhcpTransactionId++;
70-
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
119+
// We'll use the transaction ID that the offer came with,
120+
// rather than the one we were up to
121+
_dhcpTransactionId = respId;
122+
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - _startTime) / 1000));
71123
_dhcp_state = STATE_DHCP_REQUEST;
72124
}
73-
else if(_dhcp_state == STATE_DHCP_DISCOVER)
125+
}
126+
else if(_dhcp_state == STATE_DHCP_REQUEST)
127+
{
128+
uint32_t respId;
129+
messageType = tryParseDHCPResponse(respId);
130+
if(messageType == DHCP_ACK)
74131
{
75-
uint32_t respId;
76-
messageType = parseDHCPResponse(_responseTimeout, respId);
77-
if(messageType == DHCP_OFFER)
78-
{
79-
// We'll use the transaction ID that the offer came with,
80-
// rather than the one we were up to
81-
_dhcpTransactionId = respId;
82-
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
83-
_dhcp_state = STATE_DHCP_REQUEST;
132+
_dhcp_state = STATE_DHCP_LEASED;
133+
result = 1;
134+
//use default lease time if we didn't get it
135+
if(_dhcpLeaseTime == 0){
136+
_dhcpLeaseTime = DEFAULT_LEASE;
84137
}
85-
}
86-
else if(_dhcp_state == STATE_DHCP_REQUEST)
87-
{
88-
uint32_t respId;
89-
messageType = parseDHCPResponse(_responseTimeout, respId);
90-
if(messageType == DHCP_ACK)
91-
{
92-
_dhcp_state = STATE_DHCP_LEASED;
93-
result = 1;
94-
//use default lease time if we didn't get it
95-
if(_dhcpLeaseTime == 0){
96-
_dhcpLeaseTime = DEFAULT_LEASE;
97-
}
98-
//calculate T1 & T2 if we didn't get it
99-
if(_dhcpT1 == 0){
100-
//T1 should be 50% of _dhcpLeaseTime
101-
_dhcpT1 = _dhcpLeaseTime >> 1;
102-
}
103-
if(_dhcpT2 == 0){
104-
//T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
105-
_dhcpT2 = _dhcpT1 << 1;
106-
}
107-
_renewInSec = _dhcpT1;
108-
_rebindInSec = _dhcpT2;
138+
//calculate T1 & T2 if we didn't get it
139+
if(_dhcpT1 == 0){
140+
//T1 should be 50% of _dhcpLeaseTime
141+
_dhcpT1 = _dhcpLeaseTime >> 1;
142+
}
143+
if(_dhcpT2 == 0){
144+
//T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
145+
_dhcpT2 = _dhcpT1 << 1;
109146
}
110-
else if(messageType == DHCP_NAK)
111-
_dhcp_state = STATE_DHCP_START;
147+
_renewInSec = _dhcpT1;
148+
_rebindInSec = _dhcpT2;
112149
}
113-
114-
if(messageType == 255)
115-
{
116-
messageType = 0;
150+
else if(messageType == DHCP_NAK)
117151
_dhcp_state = STATE_DHCP_START;
118-
}
119-
120-
if(result != 1 && ((millis() - startTime) > _timeout))
121-
break;
122152
}
123153

124-
// We're done with the socket now
125-
_dhcpUdpSocket.stop();
126-
_dhcpTransactionId++;
127-
154+
if(messageType == 255 && ((millis() - _startResponseTime) > _responseTimeout))
155+
{
156+
_dhcp_state = STATE_DHCP_START; // response timeout, restart DHCP
157+
}
128158
return result;
129159
}
130160

@@ -250,20 +280,13 @@ void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
250280
_dhcpUdpSocket.endPacket();
251281
}
252282

253-
uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
254-
{
283+
uint8_t DhcpClass::tryParseDHCPResponse(uint32_t& transactionId) {
284+
255285
uint8_t type = 0;
256286
uint8_t opt_len = 0;
257287

258-
unsigned long startTime = millis();
259-
260-
while(_dhcpUdpSocket.parsePacket() <= 0)
261-
{
262-
if((millis() - startTime) > responseTimeout)
263-
{
264-
return 255;
265-
}
266-
delay(50);
288+
if (_dhcpUdpSocket.parsePacket() <= 0) {
289+
return 255;
267290
}
268291
// start reading in the packet
269292
RIP_MSG_FIXED fixedMsg;
@@ -382,13 +405,12 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
382405
}
383406

384407

408+
385409
/*
386410
returns:
387411
0/DHCP_CHECK_NONE: nothing happened
388-
1/DHCP_CHECK_RENEW_FAIL: renew failed
389-
2/DHCP_CHECK_RENEW_OK: renew success
390-
3/DHCP_CHECK_REBIND_FAIL: rebind fail
391-
4/DHCP_CHECK_REBIND_OK: rebind success
412+
1/DHCP_CHECK_RENEW_STARTED: a new renew was initiated, call successful()
413+
2/DHCP_CHECK_REBIND_STARTED: a new rebind was initiated, call successful()
392414
*/
393415
int DhcpClass::checkLease(){
394416
//this uses a signed / unsigned trick to deal with millis overflow
@@ -424,15 +446,17 @@ int DhcpClass::checkLease(){
424446
//if we have a lease but should renew, do it
425447
if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
426448
_dhcp_state = STATE_DHCP_REREQUEST;
427-
rc = 1 + request_DHCP_lease();
449+
init_new_DHCP_request();
450+
rc = 1;
428451
}
429452

430453
//if we have a lease or is renewing but should bind, do it
431454
if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
432455
//this should basically restart completely
433456
_dhcp_state = STATE_DHCP_START;
434457
reset_DHCP_lease();
435-
rc = 3 + request_DHCP_lease();
458+
init_new_DHCP_request();
459+
rc = 2;
436460
}
437461
}
438462
else{

libraries/Ethernet/Dhcp.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#define STATE_DHCP_LEASED 3
1414
#define STATE_DHCP_REREQUEST 4
1515
#define STATE_DHCP_RELEASE 5
16+
#define STATE_DHCP_CONNECTION_FAILED 6
17+
#define STATE_DHCP_TIMEOUT 7
1618

1719
#define DHCP_FLAGSBROADCAST 0x8000
1820

@@ -52,6 +54,8 @@
5254
#define DHCP_CHECK_RENEW_OK (2)
5355
#define DHCP_CHECK_REBIND_FAIL (3)
5456
#define DHCP_CHECK_REBIND_OK (4)
57+
#define DHCP_CHECK_RENEW_STARTED (1)
58+
#define DHCP_CHECK_REBIND_STARTED (2)
5559

5660
enum
5761
{
@@ -156,14 +160,18 @@ class DhcpClass {
156160
unsigned long _secTimeout;
157161
uint8_t _dhcp_state;
158162
EthernetUDP _dhcpUdpSocket;
163+
uint32_t _startTime;
164+
uint32_t _startResponseTime;
159165

166+
void init_new_DHCP_request();
160167
int request_DHCP_lease();
168+
int step_DHCP_lease();
161169
void reset_DHCP_lease();
162170
void presend_DHCP();
163171
void send_DHCP_MESSAGE(uint8_t, uint16_t);
164172
void printByte(char *, uint8_t);
165173

166-
uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId);
174+
uint8_t tryParseDHCPResponse(uint32_t& transactionId);
167175
public:
168176
IPAddress getLocalIp();
169177
IPAddress getSubnetMask();
@@ -172,6 +180,15 @@ class DhcpClass {
172180
IPAddress getDnsServerIp();
173181

174182
int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
183+
184+
// non blocking variant, call successful afterwards
185+
void initialize(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) ;
186+
187+
// 0 = not finished, 1 = finished and successful, 2 = finished but failed
188+
int successful();
189+
190+
// 0 = nothing needed, 1 = renew started, 2 = rebind started, if >0 call successful to wait for
191+
// finishing the rebind/release
175192
int checkLease();
176193
};
177194

0 commit comments

Comments
 (0)