I have the w5100 etherenet card, both the arduino (first version I think) and the seeedstudio v1.1 and I have issues with the ethernet card freezing up and not responding. The code on the arduino still runs though. Circuit mods aside, is it possible in the code to reinitialize the ethernet card without rebooting the arduino? Does the library support calling ethernet.begin(mac); again? Thanks.
You can call Ethernet.begin() again, but it is better to use code that doesn't freeze. If the Arduino code is still running and it can't accept or establish a connection with the w5100, then you are probably running out of sockets due to faulty code.
It may be better to post the sketch code you are trying.
How am I running out of sockets? Doesn't client.stop(); work?
Jeremy-arduino:
How am I running out of sockets? Doesn't client.stop(); work?
Not always. I found if there are characters left in the w5100 socket rx buffer when you call client.stop(), the socket will not close correctly and becomes unavailable.
Well here is my code. It's a little sloppy. I have omitted my authentication methods from this posting.
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0x00, 0x00, 0x65, 0x00, 0x00, 0x01 };
//byte ip[] = { 10, 125, 103, 58 };
//byte dnsServer[] = { 10, 125, 165, 5 };
//byte gateway[] = { 10, 125, 103, 1 };
//byte subnet[] = { 255, 255, 255, 0 };
IPAddress server(xxx, xxx, xxx, 86); // PHP SQL Server
unsigned int localPort = 8888; // local port to listen for UDP packets
IPAddress timeServer(xxx, xxx, xxx, 86); // NTP server
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
// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
EthernetClient client;
// Digital Inputs
int dRead1 = 3;
int dRead2 = 5;
int dRead3 = 6;
int dRead4 = 7;
int dRead5 = 8;
int dRead6 = 9;
// Temperature Name Values
float tRead1 = 0.0;
float tRead2 = 0.0;
// Quearter hour updates
int lastMinute = 0;
int nextMinute = 0;
int syncTimeLastMinute = 0;
boolean flagBit = false;
boolean doSync = true;
boolean tempAlarmSent0 = false;
boolean tempAlarmSent1 = false;
// Temperature alarm threshold values
float sensorAlarmThreshold0 = 77.0;
float sensorAlarmThreshold1 = 67.0;
// Data wire is plugged into pin 3 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
DeviceAddress masterControl = { 0x28, 0xF7, 0xFA, 0xFA, 0x04, 0x00, 0x00, 0x06 };
DeviceAddress equipmentRoom = { 0x28, 0x92, 0x14, 0xFB, 0x04, 0x00, 0x00, 0xD9 };
// vars for reading temps
float temp = 0.0;
int tempTime = 00;
// vars for leds
int led1Value = 0;
int led2Value = 1;
void setup()
{
digitalWrite(4, HIGH); // lock out SD Card
pinMode(4, OUTPUT);
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.println("Booting");
// Start up the library
sensors.begin();
// set the resolution to 10 bit (good enough?)
sensors.setResolution(masterControl, 12);
sensors.setResolution(equipmentRoom, 12);
// Set input states
pinMode(dRead1, INPUT);
//digitalWrite(dRead1, HIGH);
pinMode(dRead2, INPUT);
digitalWrite(dRead2, HIGH);
pinMode(dRead3, INPUT);
digitalWrite(dRead3, HIGH);
pinMode(dRead4, INPUT);
digitalWrite(dRead4, HIGH);
pinMode(dRead5, INPUT);
digitalWrite(dRead5, HIGH);
pinMode(dRead6, INPUT);
digitalWrite(dRead6, HIGH);
// Turn on LEDS
pinMode(A4, OUTPUT);
digitalWrite(A4, HIGH);
pinMode(A5, OUTPUT);
digitalWrite(A5, HIGH);
// start Ethernet and UDP
//Ethernet.begin(mac, ip, dnsServer, gateway, subnet);
Ethernet.begin(mac);
Udp.begin(localPort);
delay(1000);
Serial.println("Getting ready to sync time...");
syncTime();
Serial.println("Getting ready to get temps...");
getTemps();
delay(50);
dRead1 = digitalRead(3);
dRead2 = digitalRead(5);
dRead3 = digitalRead(6);
dRead4 = digitalRead(7);
dRead5 = digitalRead(8);
dRead6 = digitalRead(9);
sendUpdate("b"); // Send "bootup" update
Serial.println("Starting main loop...");
Serial.println();
}
void loop(){
if(Serial.available() > 0){
char c = Serial.read();
if(c == 'u'){
sendUpdate("s");
Serial.println("Serial send command...");
printTime("Serial Input", 1);
}
}
int currentMinute = minute();
if(currentMinute == 0 || currentMinute == 15 || currentMinute == 30 || currentMinute== 45){
if(currentMinute != lastMinute){
//flagBit = true;
sendUpdate("q");
lastMinute = currentMinute;
//Serial.println("Quarter Hour...");
//printTime();
}
}
inputRead();
// Get temps once a minute
int currentSecond = second();
if(currentSecond == 15 && tempTime != minute()){
tempTime = minute();
//printTime();
getTemps();
}
// Set time sync flag to true
if(minute() == 1){
doSync = true;
}
// If time sync flag is true and if it's time, set flag to false and sync time
if(minute() == 0 && second() == 8 && doSync == true){
doSync = false;
syncTime();
}
// If update flag is true, send update alarm
if (flagBit == true)
{
sendUpdate("a");
}
}
// Send update alarm, can be triggered by serial command or logic input
void sendUpdate(String type){
flagBit = false;
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
//Serial.println("connected");
// Make a HTTP request:
client.print("GET /ktvl/telemetry/telemetry.php?id=1");
client.print("&d1=");
client.print(dRead1);
client.print("&d2=");
client.print(dRead2);
client.print("&d3=");
client.print(dRead3);
client.print("&d4=");
client.print(dRead4);
client.print("&d5=");
client.print(dRead5);
client.print("&d6=");
client.print(dRead6);
client.print("&t1=");
client.print(tRead1);
client.print("&t2=");
client.print(tRead2);
client.print("&ip=");
client.print(Ethernet.localIP());
client.print("&type=");
client.print(type);
client.println(" HTTP/1.1");
client.println("Host: www.towerboy.com");
client.println("Connection: close");
client.println();
while(client.connected()){
while(client.available()){
Serial.write(client.read());
}
}
delay(50);
client.stop();
delay(50);
// print status to serial monitor
Serial.println("Update Sent.");
Serial.print("GET /ktvl/telemetry/telemetry.php?id=1");
Serial.print("&d1=");
Serial.print(dRead1);
Serial.print("&d2=");
Serial.print(dRead2);
Serial.print("&d3=");
Serial.print(dRead3);
Serial.print("&d4=");
Serial.print(dRead4);
Serial.print("&d5=");
Serial.print(dRead5);
Serial.print("&d6=");
Serial.print(dRead6);
Serial.print("&t1=");
Serial.print(tRead1);
Serial.print("&t2=");
Serial.print(tRead2);
Serial.print("&ip=");
Serial.print(Ethernet.localIP());
Serial.print("&type=");
Serial.println(type);
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
Continued in next post...
// Send alarm email
void sendAlarm(String source, int value){
//flagBit = false;
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
//Serial.println("connected");
// Make a HTTP request:
client.print("GET /ktvl/telemetry/alarmLogicRX.php?id=1");
client.print("&alarmSource=");
client.print(source);
client.print("&alarmValue=");
client.print(value);
client.print("&ip=");
client.print(Ethernet.localIP());
client.println(" HTTP/1.1");
client.println("Host: www.towerboy.com");
client.println("Connection: close");
client.println();
while(client.connected()){
while(client.available()){
Serial.write(client.read());
}
}
delay(50);
client.stop();
delay(50);
// print status to serial monitor
Serial.print("sendAlarm ");
Serial.println(source);
Serial.println();
Serial.print("GET /ktvl/telemetry/alarmLogicRX.php?id=1");
Serial.print("&alarmSource=");
Serial.print(source);
Serial.print("&alarmValue=");
Serial.println(value);
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
// Send Temp alarm email
void sendTempAlarm(String source, float value, String tempMsg, float tempThreshold){
//flagBit = false;
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
//Serial.println("connected");
// Make a HTTP request:
client.print("GET /ktvl/telemetry/alarmTempRX.php?id=1");
client.print("&alarmSource=");
client.print(source);
client.print("&alarmValue=");
client.print(value);
client.print("&msg=");
client.print(tempMsg);
client.print("&threshold=");
client.print(tempThreshold);
client.print("&ip=");
client.print(Ethernet.localIP());
client.println(" HTTP/1.1");
client.println("Host: www.towerboy.com");
client.println("Connection: close");
client.println();
while(client.connected()){
while(client.available()){
Serial.write(client.read());
}
}
delay(50);
client.stop();
delay(50);
// print status to serial monitor
Serial.print("sendAlarm ");
Serial.println(source);
Serial.println();
Serial.print("GET /ktvl/telemetry/alarmTempRX.php?id=1");
Serial.print("&alarmSource=");
Serial.print(source);
Serial.print("&alarmValue=");
Serial.println(value);
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
// Read logic input alarms
void inputRead(){
if(dRead1 != digitalRead(3)){
dRead1 = digitalRead(3);
flagBit = true;
sendAlarm("d1", dRead1);
printTime("Input 1", dRead1);
}
if(dRead2 != digitalRead(5)){
dRead2 = digitalRead(5);
flagBit = true;
sendAlarm("d2", dRead2);
printTime("Input 2", dRead2);
}
digitalWrite(A4, dRead2);
if(dRead3 != digitalRead(6)){
dRead3 = digitalRead(6);
flagBit = true;
sendAlarm("d3", dRead3);
printTime("Input 3", dRead3);
}
if(dRead4 != digitalRead(7)){
dRead4 = digitalRead(7);
flagBit = true;
sendAlarm("d4", dRead4);
printTime("Input 4", dRead4);
}
if(dRead5 != digitalRead(8)){
dRead5 = digitalRead(8);
flagBit = true;
sendAlarm("d5", dRead5);
printTime("Input 5", dRead5);
}
if(dRead6 != digitalRead(9)){
dRead6 = digitalRead(9);
flagBit = true;
sendAlarm("d6", dRead6);
printTime("Input 6", dRead6);
}
}
// Turn on A5 LED while getting temps, call function to get temps
void getTemps(){
digitalWrite(A5, HIGH);
sensors.requestTemperatures();
printTemperature(masterControl);
tRead1 = temp;
printTemperature(equipmentRoom);
tRead2 = temp;
//aRead2 = analogRead(2);
//aRead3 = analogRead(3);
//aRead4 = analogRead(4);
//aRead5 = analogRead(5);
tempAlarm();
digitalWrite(A5, LOW);
}
// Evaluate if temps are out of thresholds and send updates and email if true
void tempAlarm(){
if(!tempAlarmSent0 && tRead1 > sensorAlarmThreshold0){
sendTempAlarm("a0", tRead1, " is above ", sensorAlarmThreshold0);
tempAlarmSent0 = true;
flagBit = true;
}else if(tempAlarmSent0 && tRead1 < (sensorAlarmThreshold0 - 5)){
sendTempAlarm("a0", tRead1, " is below ", (sensorAlarmThreshold0 - 1));
tempAlarmSent0 = false;
flagBit = true;
}
if(!tempAlarmSent1 && tRead2 > sensorAlarmThreshold1){
sendTempAlarm("a1", tRead2, " is above ", sensorAlarmThreshold1);
tempAlarmSent1 = true;
flagBit = true;
}else if(tempAlarmSent1 && tRead2 < (sensorAlarmThreshold1 - 5)){
sendTempAlarm("a1", tRead2, " is below ", (sensorAlarmThreshold1 - 3));
tempAlarmSent1 = false;
flagBit = true;
}
}
// Function to get temps
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
temp = (DallasTemperature::toFahrenheit(tempC));
}
// Function to sync with NTP
void syncTime(){
sendNTPpacket(timeServer); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1100);
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;
Serial.print("Seconds since Jan 1 1900 = " );
Serial.println(secsSince1900);
// 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:
epoch = epoch - 25200;
Serial.println(epoch);
setTime(epoch);
// print the hour, minute and second:
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
Serial.print(':');
if ( ((epoch % 3600) / 60) < 10 ) {
// In the first 10 minutes of each hour, we'll want a leading '0'
Serial.print('0');
}
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
Serial.print(':');
if ( (epoch % 60) < 10 ) {
// In the first 10 seconds of each minute, we'll want a leading '0'
Serial.print('0');
}
Serial.println(epoch %60); // print the second
}
// wait ten seconds before asking for the time again
//delay(10000);
Serial.println("Time was synced");
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(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();
}
// Function to print user friendly time to Serial Monitor
void printTime(String triggerSource, int sourceValue){
Serial.print(triggerSource);
Serial.print(": ");
Serial.print(sourceValue);
Serial.print(" at ");
Serial.print(hour());
Serial.print(":");
if(minute() < 10)
Serial.print("0");
Serial.print(minute());
Serial.print(":");
if(second() < 10)
Serial.print("0");
Serial.println(second());
Serial.println();
}
What is the message on the serial monitor when that code stops working?
As in my original post, the code still runs on the arduino. It still gets the temperature once a minute, it tries to send the updates to temp or logic alarms but fails because the ethernet card stops responding. I can let it run till it dies again and copy the output from the Serial Monitor if you would like.
I'm not sure that is necessary. Does it say "connected" or "connection failed" when it stop sending data?
edit: Add this to your sketch and call this function just before attempting to connect with the ethernet.
#include <utility/w5100.h>
byte socketStat[MAX_SOCK_NUM];
void ShowSockStatus()
{
for (int i = 0; i < MAX_SOCK_NUM; i++) {
Serial.print(F("Socket#"));
Serial.print(i);
uint8_t s = W5100.readSnSR(i);
socketStat[i] = s;
Serial.print(F(":0x"));
Serial.print(s,16);
Serial.print(F(" "));
Serial.print(W5100.readSnPORT(i));
Serial.print(F(" 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(F("("));
Serial.print(W5100.readSnDPORT(i));
Serial.println(F(")"));
}
}
A socket status list:
0X0 = available.
0x14 = socket waiting for a connection
0x17 = socket connected to a server.
0x22 = socket using udp
OK, I will add that. It usually takes a day or two to crash on me so I'll post the results then...
OK, Just got back to work today and got the Serial Ouput. I attached it as a text file. I also removed the IP addresses that I am using and replaced them with "x"...
ethernetDebug.txt (3.96 MB)
Your code has run out of sockets.
New Connection Attempt...
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x17 6369 D:xxx.xxx.xxx.86(80)
Socket#2:0x17 10556 D:xxx.xxx.xxx.86(80)
Socket#3:0x17 13767 D:xxx.xxx.xxx.86(80)
connection failed
I know, but why? If I read my sketch correctly, I should only be using two sockets at any given time. Why are they not closing and how can I remedy this?
Here is how your output started. Only the UDP socket is not available for TCP use.
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
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)
Here is the first occurrence of a socket becoming unavailable: Socket#1 is now unavailable.
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x17 6369 D:xxx.xxx.xxx.86(80)
Socket#2:0x0 8857 D:xxx.xxx.xxx.86(80)
Socket#3:0x0 0 D:0.0.0.0(0)
Then you run out of sockets.
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x17 6369 D:xxx.xxx.xxx.86(80)
Socket#2:0x17 10556 D:xxx.xxx.xxx.86(80)
Socket#3:0x17 13767 D:xxx.xxx.xxx.86(80)
Note there is no socket with the status of 0x0. Your code is not closing the connections correctly, normally because you have left characters in the socket's rx buffer when you called client.stop(). Socket#0 is the UDP socket. Socket#1 to #3 are still connected to a server.
edit: This can also be caused by running out of SRAM or overflowing an array.
I understand that the sockets are not closing correctly, but I also thought that writing the buffer to the serial port would clear them out... Am I wrong there? Only after I write everything in the buffer to the serial port, do I call client.stop();. If it's not done writing the buffer to the serial port, why does the Arduino move on? Should I increase my delays where I write the data?
Actually, what part of the code you posted looks ok as far as wasting sockets. Just out of curiosity, what model Arduino are you using? Is it an Uno? If so you could be running out of SRAM. There appears to be a lot of static strings in your code that might cause a SRAM wraparound and corrupted variable data in low SRAM.
Even using a Mega as I do, I still do not like wasting SRAM. I always recommend using the F() function with static strings. For example in your setup function, you have this call. I would use the second example.
// This moves the string "Booting" into SRAM before printing
Serial.println("Booting");
// This prints directly from program memory.
Serial.println(F("Booting"));
I recommend going through your code and adding the F() function to all your static strings and run the code again.
Actually the Arduino I got that dump from is a mega 2560, but I have an Uno sitting on my desk that ran for the entire month of February without issue... I will try using the F() function and see how that goes...
Edit:
Is there a way to force a specific socket closed?
Jeremy-arduino:
Actually the Arduino I got that dump from is a mega 2560, but I have an Uno sitting on my desk that ran for the entire month of February without issue... I will try using the F() function and see how that goes...Edit:
Is there a way to force a specific socket closed?
That is odd. The Mega should have run the code better. I haven't needed to force a socket closed yet.
It took me a bit of reading to find this. This is at line 197,723 of your text file. Note the socket loss is after a connection fail. Only the udp socket#0 used before the fail, and socket#1 used after the fail.
New Connection Attempt...
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x0 6368 D:xxx.xxx.xxx.86(80)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
connection failed
New Connection Attempt...
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x17 6369 D:xxx.xxx.xxx.86(80)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Then you lost two sockets at line 290,023 in one connection attempt
New Connection Attempt...
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x17 6369 D:xxx.xxx.xxx.86(80)
Socket#2:0x0 8864 D:xxx.xxx.xxx.86(80)
Socket#3:0x0 0 D:0.0.0.0(0)
HTTP/1.1 200 OK
Date: Mon, 03 Mar 2014 18:01:51 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.3.10
Vary: Host
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8
Update Sent.
GET /ktvl/telemetry/telemetry.php?id=1&d1=0&d2=0&d3=0&d4=0&d5=0&d6=0&t1=77.22&t2=65.75&ip=192.168.1.52&type=a
New Connection Attempt...
Socket#0:0x22 8888 D:xxx.xxx.xxx.86(123)
Socket#1:0x17 6369 D:xxx.xxx.xxx.86(80)
Socket#2:0x17 10556 D:xxx.xxx.xxx.86(80)
Socket#3:0x17 13767 D:xxx.xxx.xxx.86(80)
connection failed
Which version of the IDE are you using?
Do you have a SD card in the shield's slot?
No I do not have an sd card nor do I plan to use one as this project is internet based... I have noticed that socket 0 is still usable and the ntp does in fact still work after all the other sockets are failed...
As far as the mega supposedly running the code better, the mega has a considerable amount more activity than the Uno, if that has any significance...
Edit:
Sorry, IDE version 1.0.5
NTP is udp, so it should use socket#0, and according to your serial output, it is. Note the last destination port of socket#0 is 123. That is NTP.
I am trying to figure out why your code took two sockets to attempt one tcp connection at line 290,023. I haven't seen that before. Mine has always taken only one socket, and that was all that was lost in one connection attempt in my tests.
The only thing I don't do is use the String data type. It has always caused a crash, but normally in the Arduino, not in the w5100.