Go Down

Topic: Thumbs way down for Arduino WiFi shield. Read before you buy (Read 40496 times) previous topic - next topic

SurferTim

#45
Nov 19, 2013, 12:31 pm Last Edit: Nov 19, 2013, 02:36 pm by SurferTim Reason: 1
Thanks to PaulS, I will have a wifi shield arriving at the end of this week. Thanks, Paul. You do more than your share here on the forum.

The first code I plan on running is this. It is a firmware version check. I would like some input from those whose shields work, and those whose shields fail. Which version do you have and does it work?
Code: [Select]
#include <WiFi.h>

int status = WL_IDLE_STATUS;     // the Wifi radio's status

void setup() {
 //Initialize serial and wait for port to open:
 Serial.begin(9600);
 
 // check for the presence of the shield:
 if (WiFi.status() == WL_NO_SHIELD) {
   Serial.println(F("WiFi shield not present"));
   // don't continue:
   while(true);
 }

 // check firmware version
 Serial.print(F("Firmware version: "));
 Serial.println(WiFi.firmwareVersion());
}

void loop() {
}


edit: From another post here on the forum, that should return V1.1.0 if you have completed the firmware upgrade included with IDE v1.0.5.


MattS-UK

#46
Nov 19, 2013, 09:00 pm Last Edit: Nov 20, 2013, 07:52 am by MattS-UK Reason: 1
Quote from: SurferTim

You correct about fast and loose. But I am working with very limited resources, so...

So.  You could respond with HTTP/1.0 and conform with the HTTP protocol standards using no more resources.  It takes more resource to conform with HTTP/1.1 and the protocol offers no benefits (I can think of) for low powered devices.

Quote
If the w5100 is sending smaller packets than it should, that would be in the firmware. The SD page uploads should load the tx buffer with 64 bytes, then send the w5100 an exec command to send that packet. ??

The single character packets are down to your use of println when you could be using write.

For a few days only, you can reach my Arduino Ethernet shield on
http://212.159.25.45
If you look at the response in Wireshark, you will see it arrives in a single packet.  I am short of time tonight but I will post the sketch tomorrow.

Great news on the WiFi Shield donation by the way.

I have two WiFi shields, both R3.
They worked OK with the firmware they shipped with and reported V1.0.0
They went flaky when I upgraded to the firmware development snapshot on Github and continued to report V1.0.0
They worked reliably again when I upgraded to the firmware in the Arduino master branch on Github but continued to report V1.0.0
They stopped working when I upgraded to Arduino IDE 1.0.5
They are working OK again since I upgraded them using the firmware files shipped with the IDE [edit] and they report V1.1.0

When I say, work OK, I mean they work within the limitations that they have.  Learning what those limitations are has taken me quite some time though.


SurferTim

#47
Nov 19, 2013, 11:22 pm Last Edit: Nov 20, 2013, 12:29 am by SurferTim Reason: 1
The client.println() calls should not be sending single character packets. Only client.write(char) should do that. The client.write(char*,int) calls should send int number of characters (64 for my code) per packet (edit: except the last one if the file was not an even multiple of 64).

I will consider switching to HTTP/1.0 tho. That makes sense.

So you never show v1.1.0 on the wifi shield firmware?

edit: I tried you server. It works ok through the PuTTY test. It responds like zoomkat's code. It does not wait for the blank line, only the first line feed, and disregards the rest of the request.

I gotta know how you are servicing more than one socket at a time. Would you be ok with posting your server code?
edit: Never mind. I just found out by testing mine. I just learned something about the w5100 and ethernet library.

SurferTim

Quote
For a few days only, you can reach my Arduino Ethernet shield on
http://xx.xx.xx.xx

Did you terminate your test early? Or did I get all your sockets? I can crash mine too.  :(

MattS-UK

#49
Nov 20, 2013, 09:01 am Last Edit: Nov 20, 2013, 09:03 am by MattS-UK Reason: 1

The client.println() calls should not be sending single character packets.


:smile:  Wireshark is your friend.  Whatever println should do, here is what it is doing.
Code: [Select]

//This is the result of a println()
   00000000  48                                               H
   00000001  54                                               T
   00000002  54                                               T
   00000003  50                                               P
   00000004  2f                                               /
   00000005  31                                               1
   00000006  2e                                               .
   00000007  31                                               1
//...snip...
//And this is what a write() looks like
   0000003F  3c 48 54 4d 4c 3e 0a 3c  48 45 41 44 3e 3c 6c 69 <HTML>.< HEAD><li
   0000004F  6e 6b 20 72 65 6c 3d 22  73 74 79 6c 65 73 68 65 nk rel=" styleshe
   0000005F  65 74 22 20 74 79 70 65  3d 22 74 65 78 74 2f 63 et" type ="text/c
   0000006F  73 73 22 20 68 72 65 66  3d 22 64 65 66 63 73 73 ss" href ="defcss
   0000007F  2e 63 73 73 22 3e 3c 2f  48 45 41 44 3e 0a 0a 3c .css"></ HEAD>..<
   //...snip


Quote
I will consider switching to HTTP/1.0 tho. That makes sense.

You would not be the first developer I had to try to explain HTTP version numbers to.  Outside of HTTP, version numbers typically refer to compatibility.  e.g. V2 may not be compatible with V1.  HTTP was designed to be inherently backwards compatible.  So a V1.1 request remains compatible with a V1.0 response.  HTTP/1.0, infers fewer expectations.  For instance, a server declaring a V1.0 response may still support pipelining but does not have to.  A server declaring a HTTP/1.1 response, should support pipelining.

Quote
So you never show v1.1.0 on the wifi shield firmware?

An oversight, corrected.   My shields are reporting V1.1.0 since the latest upgrade.  The latest firmware version is the most stable and complete, in my opinion.   People appear to be having issues upgrading and that appears to have created some myth and legend about earlier versions being better.  

The latest firmware version still has issues though.  The 2 second latency between transmit cycles  being the most serious, in my view.
http://mssystems.emscom.net/helpdesk/knowledgebase.php?article=51
I would love to have a crack at the WiFi shield's MCU firmware but would not know where to start with compiling and debugging.

Quote
edit: I tried you server. It works ok through the PuTTY test. It responds like zoomkat's code. It does not wait for the blank line, only the first line feed, and disregards the rest of the request.
My server is not really a server.  It's a couple house spend on a proof of concept.  The sketch started out as a simple client throughput test.  I added just enough server code to send a response to a browser.

Quote
I gotta know how you are servicing more than one socket at a time.

I didn't know I was!  This is the first time I have tried to do anything with the Ethernet shield and I am still trying to fathom the relationship between the library and the socket structures it is abstracting.  To be honest, I would be more comfortable working directly with the sockets.

Quote
Would you be ok with posting your server code?
edit: Never mind. I just found out by testing mine. I just learned something about the w5100 and ethernet library.

My sketch will be in the next post but the server code is non-existent.  Please do share what you know about the library.


MattS-UK

#50
Nov 20, 2013, 09:26 am Last Edit: Nov 20, 2013, 12:58 pm by MattS-UK Reason: 1
Sketch as promised.  
It is intended to be a demonstration of using Client.write() to avoid using Client.println().
It started as a throughput test with the sendData() function.  
Naturally progressed to utilising program memory to send HTML over HTTP.
Then I had a what the heck, can I send this to a browser moment.

Code: [Select]

#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdlib.h>
#include <Streaming.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <Dns.h>
#include <Time.h>

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

//EthernetClient client;
EthernetServer server(80);

void setup()
{
Serial.begin(9600);
Serial << F("Setup...\r\n");

Ethernet.begin(mac);

IPAddress ip = Ethernet.localIP();

Serial << F("Arduino IP ");
for (uint8_t i =0; i <4; i++) {
Serial << ip[i] << ".";
}
Serial << "\r\n";

server.begin();
}

uint16_t responseCount = 0;
uint16_t timeoutCount = 0;
boolean idle;

void loop()
{
if (!idle) {
Serial << F("Responses ") << responseCount
<< F("\tTimeouts ") << timeoutCount
<< F("\tFree Ram ") << ramTest()
<< F("\r\nListening\r\n");
idle = true;
};

EthernetClient client = server.available();
if (client.connected()) {
idle = false;
char* page = getPageM(0);

uint16_t bytes = sendResponse(&client, 200, page);
Serial << "\r\nSent " <<  bytes << " bytes to host\r\n";
free(page);

boolean wait = true;
uint16_t startWait = millis();
do {
client.flush();
wait =(millis() - startWait) < 2000;
} while(client.connected() && wait);
client.stop();
responseCount++;
if (!wait) timeoutCount++;
}
}

char* getPageM(uint8_t pageNumber) {
char* page = NULL;

switch(pageNumber) {
case 0:
page = (char*) malloc(95);
sprintf_P(page,
(char*) F("<HTML><BODY><h1>Matt's Arduino</h1><p>Up Time %02d:%02d:%02d</p><p>Ram Free = %d</p></BODY></HTML>"),
hour(), minute(), second(),
ramTest()
);
}
return page;
}

uint16_t sendResponse(Client* client, uint16_t status, char* page) {
uint16_t sent = 0;
char* response = (char*) malloc(64);

switch (status) {
case 200:
sprintf_P(response,
(char*) F("http/1.1 %d OK\r\ncontent-length:%d\r\ncontent-type:text/html\r\nconnection:close\r\n\r\n"),
200,
strlen(page)
);
strcat(response, page);   //probably not safe!
break;
}
sent = client->write((byte*) response, strlen(response));

Serial << response;
free(response);
return sent;
}

uint16_t sendData (Client* client, uint16_t dataLen, uint8_t maxLoop ){

byte* data = NULL;
uint32_t bytesSent = 0;

data = (byte*) malloc(dataLen);
for (uint16_t i = 0; i < dataLen; i++) {
data[i] = 'A';
}

for (uint8_t l = 0; l < maxLoop; l++) {
bytesSent += client->write(data, dataLen);
}
free(data);
return bytesSent;
}

IPAddress hostByName(char* hostName) {
IPAddress hostIP;
DNSClient resolver;
resolver.begin(Ethernet.dnsServerIP());
resolver.getHostByName(hostName, hostIP);
return hostIP;
};

uint16_t ramTest() {

uint16_t freeRam = 0;
byte* buffer = NULL;

do {
buffer = (byte*) malloc(++freeRam);
if (buffer != NULL) {
free(buffer);
}
} while (buffer != NULL);

return freeRam + sizeof(byte*) + sizeof(uint16_t);
}

SurferTim

#51
Nov 20, 2013, 11:40 am Last Edit: Nov 20, 2013, 12:17 pm by SurferTim Reason: 1
@MattS-UK: Thanks for that update on client.println(). I had checked it before several IDE versions ago, and I am almost certain it was not breaking up the packets then. So you use client.write(char*) and it doesn't break up the packets into single bytes?

But that is not my big problem today. I can crash my server code. I must find a way to fix that.
http://forum.arduino.cc/index.php?topic=197103.0

edit: I tried client.write(char*) and it does not like the F() function. So I guess my choice is single character packets or run out of SRAM.  :(

Update on the client.write(char*).  It apparently does not move program memory strings into SRAM like client.print() does, at least that is the result of my preliminary tests. I use less SRAM with client.write(char*) than client.print(F(char*)). ??

BTW, thanks for your input. This is what I was looking for.  :)

MattS-UK

#52
Nov 20, 2013, 12:43 pm Last Edit: Nov 20, 2013, 12:48 pm by MattS-UK Reason: 1
Ethernet Shield conversation moved
http://forum.arduino.cc/index.php?topic=197103.msg1475328#new
Reply #67

SurferTim

I read your code. I tried client.write(char*) compared to client.print(F(char*)) and found that the write uses less SRAM than the print. See the server thread. This part belongs there. I have been "thread hopping" (wish the Arduino could thread hop!).

Thanks for that!

liudr

The FLASH string helper F() uses String object to allocate memory so it takes more SRAM. The write(char*) simply calls write(char) repeatedly.

pYro_65


The FLASH string helper F() uses String object to allocate memory so it takes more SRAM. The write(char*) simply calls write(char) repeatedly.


No it does not!

F(), uses PSTR
Code: [Select]
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))


This writes byte by byte to 'write'.
Code: [Select]
size_t Print::print(const __FlashStringHelper *ifsh)
{
  const char PROGMEM *p = (const char PROGMEM *)ifsh;
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    n += write(c);
  }
  return n;
}

SurferTim

#56
Nov 22, 2013, 12:57 pm Last Edit: Nov 22, 2013, 02:29 pm by SurferTim Reason: 1
Just an update. I received the wifi shield from PaulS yesterday. He does more than average for this forum. Thanks, PaulS!

I have a R2 Mega and a R3 wifi shield. For those not familiar with interfacing these two, you must jumper 5v to the IOREF pin, or the wifi shield will not respond, and the test code shows "wifi shield not present".

It is using firmware v1.0.0 as I suspected. However, I found this morning that I do not have a mini-usb cable to program the wifi shield with the new firmware. That will probably be Saturday before I can get one.

edit: I found a cable and updated the firmware to v1.1.0. It was not as easy as I thought it would be. It connected to my wifi network right away and got an ip. So far, so good.

Don't have time today, but will try a sketch or two tomorrow.

SurferTim

So much for 2 second delays between sends. My first try was my basic UDP packet send. I have it set to 48 byte packets at 10 packets per second, and it is doing fine!  :)

Next will be TCP client.

SurferTim

#58
Nov 23, 2013, 12:42 pm Last Edit: Nov 23, 2013, 01:21 pm by SurferTim Reason: 1
I converted my playground web client sketch for the ethernet shield to wifi. It took only a few minutes and it is working fine.

BTW, all these are "Perfect World" sketches so far. I will move them to "Real World" (start torturing them and add fail recovery) when I determine they work ok.

Next is web server.

edit: I just finished converting my new web server code for the ethernet shield to the wifi shield. It works ok, but is a bit more sluggish than the ethernet shield. It takes about twice as long to download the images.

The email client code has been completed for a while.

SurferTim

#59
Nov 23, 2013, 10:14 pm Last Edit: Nov 23, 2013, 10:51 pm by SurferTim Reason: 1
I found a bug in the wifi library while using the tcp client sketch. If the wifi radio connection fails and the client code tries to make a client connection and it fails (which it will because the radio connection failed), the socket is not released. If that happens 4 times, you are out of sockets.

This will show the status of all the wifi sockets.
Code: [Select]
void ShowSockStatus() {
 for(int x = 0; x < MAX_SOCK_NUM; x++) {
   Serial.print(F("Socket #"));
   Serial.print(x,DEC);
   if(WiFi._state[x] == -1) Serial.println(F(": available"));
   else Serial.println(F(": used"));
 }
}


FYI: If you disable the wifi router radio (my test), wait a bit, then turn it on again, the wifi shield reconnects to the radio without a problem. No need to reconnect manually. The only problem is the failed TCP connections depleting the sockets.

I am using this as a temporary "shotgun" patch. If the connection to the server fails, I call this to reset the sockets.
Code: [Select]
void SetSockStatus() {
  for(int x = 0; x < MAX_SOCK_NUM; x++) {
    WiFi._state[x] = -1;
  }
}

Go Up