Go Down

Topic: W5100/Ethernet cannot use socket as UDP after using it as TCP (Read 5 times) previous topic - next topic

zimm0who0net

So here's the issue.  If I use any of the 4 W5100 sockets as at TCP socket that sends/receives data, it seems to disqualify that socket from sending out UDP datagrams anymore.  Calling a W5100.init() seems to fix the issue, but of course that resets all of my sockets.
Has anyone experienced this before? 

zimm0who0net

So I've dummied up a test case from some of the Arduino samples.  All this does is create a TCP server on port 80, and every 10 seconds it'll poll an NTP server via UDP.  Here's what will happen:
* It'll start listening on port 80 (W5100 socket #0)
* It'll do the NTP stuff from port 8888 on W5100 socket #1.  (this works fine).
* It'll continue to do the NTP stuff every 10 seconds indefinitely and successfully.
* If you connect to the port 80 (e.g. browse there with a web server), it'll service the request on socket 0, and open a new listening port on socket 1, and then terminate socket 0.
* The NTP stuff continues every 10 seconds, but this time it's on socket 0.  It works..
* Browse to port 80 again.  This time it'll service on socket 1.
* NTP never works again.  Web server works just fine forever...

Here's the sketch.
Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <utility/W5100.h>

void ShowSockStatus()
{
for (int i = 0; i < MAX_SOCK_NUM; i++) {
Serial.print("Socket#");
Serial.print(i);
uint8_t s = W5100.readSnSR(i);
Serial.print(":0x");
Serial.print(s,16);
Serial.print(" ");
Serial.print(W5100.readSnPORT(i));
Serial.print(" D:");
uint8_t dip[4];
W5100.readSnDIPR(i, dip);
for (int j=0; j<4; j++) {
Serial.print(dip[j],10);
if (j<3) Serial.print(".");
}
Serial.print("(");
Serial.print(W5100.readSnDPORT(i));
Serial.println(")");
}
}

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);
IPAddress timeServer(192,168,10,1);
IPAddress ip(192,168,10,20);
IPAddress gateway(192,168,10, 2);
IPAddress subnet(255, 255, 255, 0);

long timer;

void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip, INADDR_NONE, gateway, subnet);
delay(500);

Serial.println("Start!");
server.begin();
ShowSockStatus();
timer = millis();
}

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(EthernetUDP & Udp, IPAddress& address)
{

// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011;   // LI, Version, Mode
packetBuffer[1] = 0;     // Stratum, or type of clock
packetBuffer[2] = 6;     // Polling Interval
packetBuffer[3] = 0xEC;  // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:    
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
}

void checkTime()
{
EthernetUDP Udp;
Udp.begin(8888);
sendNTPpacket(Udp, timeServer); // send an NTP packet to a time server
Serial.println("");
ShowSockStatus();
// wait to see if a reply is available
delay(1000); 
if ( Udp.parsePacket() ) { 
// We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord; 

// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;     
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears; 
// print Unix time:
Serial.println(epoch); 

else
Serial.println("UDP FAIL!");
Udp.stop();

}

void loop()
{
//Check if a web client has attached.
EthernetClient client = server.available();
if (client) {
Serial.println("new Client");
ShowSockStatus();
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.print(c);
if (c == '\n' && currentLineIsBlank) {
client.stop();
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}

if ((millis() - timer) > 10000) {
timer = millis();
checkTime();
}
}

SurferTim

I loaded up your sketch and tested it. I changed only the network settings and the NTP server ip since I have my own NTP server here. It works ok, except the webpage says "No data received". I made several requests, and the NTP client is still running fine.

For those Linux users out there, you must change this include.
#include <utility/W5100.h>
to
#include <utility/w5100.h>
File names are case sensitive in linux.

zimm0who0net

How very strange.  I'm using 1.0.4 also.  I've verified this on two different Ethernet Shields and a bunch of different Megas and Unos.  I wonder if there were different versions of the W5100 chip released?  What output do you get? 

Here's mine:
Code: [Select]
Start!
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 0 D:0.0.0.0(0)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)

Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986649

Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986659

Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986669
new Client
Socket#0:0x17 80 D:192.168.10.213(9129)
Socket#1:0x14 80 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.10.20
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
If-Modified-Since: Fri, 02 Jun 2006 09:46:32 GMT

client disconnected

Socket#0:0x22 8888 D:192.168.10.1(123)
Socket#1:0x14 80 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986679
new Client
Socket#0:0x14 80 D:192.168.10.1(123)
Socket#1:0x17 80 D:192.168.10.213(9132)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.10.20
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected

Socket#0:0x14 80 D:192.168.10.1(123)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
UDP FAIL!

Socket#0:0x14 80 D:192.168.10.1(123)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
UDP FAIL!


Once it goes into fail mode it'll never come back **for that socket**.  However, if you play around with refreshing your browser you can sometimes get it to bounce to a different socket and then it'll work.  (at least until that socket also has had a TCP conversation on it)  I've also verified through tcpdump packet capture that the packet doesn't actually get sent. 

SurferTim

This worked for me. You did have some errors in that code that did not manifest themselves first pass, but did on a second. I moved the Udp.begin() to setup() and commented out the Udp.stop(). I also used my server code.
Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <utility/w5100.h>

void ShowSockStatus()
{
for (int i = 0; i < MAX_SOCK_NUM; i++) {
Serial.print("Socket#");
Serial.print(i);
uint8_t s = W5100.readSnSR(i);
Serial.print(":0x");
Serial.print(s,16);
Serial.print(" ");
Serial.print(W5100.readSnPORT(i));
Serial.print(" D:");
uint8_t dip[4];
W5100.readSnDIPR(i, dip);
for (int j=0; j<4; j++) {
Serial.print(dip[j],10);
if (j<3) Serial.print(".");
}
Serial.print("(");
Serial.print(W5100.readSnDPORT(i));
Serial.println(")");
}
}

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);
IPAddress timeServer(198,55,111,50);

IPAddress ip(192,168,2,2);
IPAddress gateway(192,168,2, 1);
IPAddress subnet(255, 255, 255, 0);

long timer;
EthernetUDP Udp;

void setup() {
Serial.begin(9600);

        pinMode(4, OUTPUT);
        digitalWrite(4, HIGH);
       
Ethernet.begin(mac, ip, INADDR_NONE, gateway, subnet);
delay(500);
Udp.begin(8888);

Serial.println("Start!");
server.begin();
ShowSockStatus();
timer = millis();
}

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(EthernetUDP & Udp, IPAddress& address)
{

// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011;   // LI, Version, Mode
packetBuffer[1] = 0;     // Stratum, or type of clock
packetBuffer[2] = 6;     // Polling Interval
packetBuffer[3] = 0xEC;  // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:    
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
}

void checkTime()
{
sendNTPpacket(Udp, timeServer); // send an NTP packet to a time server
Serial.println("");
ShowSockStatus();
// wait to see if a reply is available
delay(1000); 
if ( Udp.parsePacket() ) { 
// We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord; 

// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;     
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears; 
// print Unix time:
Serial.println(epoch); 

else
Serial.println("UDP FAIL!");
// Udp.stop();

}

void loop()
{
//Check if a web client has attached.
        checkServer();
       
if ((millis() - timer) > 10000) {
timer = millis();
checkTime();
}
}


void checkServer()
{
  EthernetClient client = server.available();
  if(client) {
    boolean currentLineIsBlank = true;
    boolean currentLineIsGet = true;
    int tCount = 0;
    char tBuf[64];
    int r,t;
    char *pch;

    Serial.print(F("Client request: "));

    // this controls the timeout
    int loopCount = 0;

    while (client.connected()) {
      while(client.available()) {
        // if packet, reset loopCount
        loopCount = 0;
        char c = client.read();

        if(currentLineIsGet && tCount < 63)
        {
          tBuf[tCount] = c;
          tCount++;
          tBuf[tCount] = 0;         
        }

        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response
          Serial.println(tBuf);
          Serial.print(F("POST data: "));
          while(client.available()) Serial.write(client.read());
          Serial.println();

          pch = strtok(tBuf,"?");

          while(pch != NULL)
          {
            if(strncmp(pch,"t=",2) == 0)
            {
              t = atoi(pch+2);
              Serial.print("t=");
              Serial.println(t,DEC);             
            }

            if(strncmp(pch,"r=",2) == 0)
            {
              r = atoi(pch+2);
              Serial.print("r=");             
              Serial.println(r,DEC);
            }


            pch = strtok(NULL,"& ");
          }
          Serial.println(F("Sending response"));
          client.print(F("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<html>"));
          client.println(F("<body><H1>TEST</H1>"));
          client.println(F("<form method=GET>T: <input type=text name=t><br>"));
          client.println(F("R: <input type=text name=r><br><input type=submit></form>"));


          client.println(F("</body></html>"));
          client.stop();
        }
        else if (c == '\n') {
          currentLineIsBlank = true;
          currentLineIsGet = false;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }

      loopCount++;

      // if 10000ms has passed since last packet
      if(loopCount > 10000) {
        // close connection
        client.stop();
        Serial.println("\r\nTimeout");
      }

      // delay 1ms for timeout timing
      delay(1);
    }
    Serial.println(F("done"));
  }
}

Go Up