WiShield + Uno = can't retrieve webpage using sample PDE (code included)

Hello Arduino Forum,

I just bought an Async WiShield 2.0 for my Uno, and uploaded the SimpleClient.pde that was included in the WiShield library. It compiles and uploads, but when I look at the Serial monitor, the program doesn’t seem to do what it’s supposed to do: namely, retrieve weather info from a government website. My code is below (with passwords & logins edited out):

/*

  • A simple sketch that uses WiServer to get the hourly weather data from LAX and prints
  • it via the Serial API
    */

#include <WiServer.h>

#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip = {192,168,1,36}; // IP address of WiShield
unsigned char gateway_ip = {192,168,1,1}; // router or gateway IP address
unsigned char subnet_mask = {255,255,255,0}; // subnet mask for the local network
const prog_char ssid PROGMEM = {“wireless”}; // max 32 bytes

unsigned char security_type = 1; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase PROGMEM = {“12345678”}; // max 64 characters, wireless router password

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

// Function that prints data from the server
void printData(char* data, int len) {

// Print the data returned by the server
// Note that the data is not null-terminated, may be broken up into smaller packets, and
// includes the HTTP header.
while (len-- > 0) {
Serial.print(*(data++));
}
}

// IP Address for www.weather.gov
uint8 ip = {140,90,113,200};

// A request that gets the latest METAR weather data for LAX
GETrequest getWeather(ip, 80, “www.weather.gov”, “/data/METAR/KLAX.1.txt”);

void setup() {
// Enable Serial output and ask WiServer to generate log messages (optional)
Serial.begin(9600);

// Initialize WiServer (we’ll pass NULL for the page serving function since we don’t need to serve web pages)

Serial.print(“Initiating WiServer\n”);
WiServer.init(NULL);
WiServer.enableVerboseMode(true);

// Have the processData function called when data is returned by the server
Serial.print(“Getting Weather\n”);
getWeather.setReturnFunc(printData);
Serial.print(“Got Weather\n”);
}

// Time (in millis) when the data should be retrieved
long updateTime = 0; //1000 millis = 1 second

void loop(){

// Run WiServer
WiServer.server_task();

// Check if it’s time to get an update
if (millis() >= updateTime) {
getWeather.submit();
getWeather.setReturnFunc(printData);
// Get another update 60 seconds from now
updateTime += 1000 * 60;
Serial.print(“updated\n”);
}

delay(10);
}

The output in the Serial monitor is this:

Initiating WiServer
Getting Weather
Got Weather
updated
Ended connection with www.weather.gov

My problem is: how come I don’t see anything, especially weather info, from the printData function?

Thank you for helping me! :slight_smile:

The first thing that you should want to know is whether printData() is even being called.

That is a very strange way to traverse a pointer when you already know the length.

Hi Paul,

In void setup, I think printData is called in this line:

getWeather.setReturnFunc(printData);

Is this sufficient to show some output in the Serial Monitor?

Also, which line were you referring to when you mentioned that was a "strange way to traverse a pointer"? I'm confused as to what you mean by that.

In void setup, I think printData is called in this line:

getWeather.setReturnFunc(printData);

No. That line defines which function to call when data is returned. It does not actually call any function.

You need to add a Serial.print() statement in the printData() function to confirm that it is actually called.

Also, which line were you referring to when you mentioned that was a “strange way to traverse a pointer”?

This code:

  while (len-- > 0) {
    Serial.print(*(data++));
  }

I’d have used something like:

for(int i=0; i<len; i++)
{
  Serial.print(data[i]);
}

Much more obvious what is happening, and the pointer is not mucked with.

Hi Paul,

You are right. I put Serial.print statements within printData() to confirm that it is actually being called…and it isn’t being called right away in the 1st try as we can tell by the output in the serial monitor. It takes until after the 2nd loop (30 seconds later) before we see the Serial.print statement “printData was called”. But, by that point, it seems the connection with the weather.gov site has already ended! What do I do to maintain the connection until printData is called?

Initiating WiServer
WiServer initiated.
Loop #1 complete.
Loop #2 complete.
Ended connection with www.weather.gov
printData was called
Did printData retrieve weather data above this sentence?
Loop #3 complete.
Loop #4 complete.
Ended connection with www.weather.gov
printData was called
Did printData retrieve weather data above this sentence?
Loop #5 complete.
Loop #6 complete.
Ended connection with www.weather.gov
printData was called
Did printData retrieve weather data above this sentence?
Loop #7 complete.
Loop #8 complete.

I changed the code in void loop so that it updates every 30 seconds, and added your code so now the code looks like this:

#include <WiServer.h>

#define WIRELESS_MODE_INFRA	1
#define WIRELESS_MODE_ADHOC	2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,1,36};	// IP address of WiShield
unsigned char gateway_ip[] = {192,168,1,1};	// router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0};	// subnet mask for the local network
const prog_char ssid[] PROGMEM = {"network"};		// max 32 bytes

unsigned char security_type = 1;	// 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"12345678"};	// max 64 characters, wireless router password

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,	// Key 0
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// Key 1
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// Key 2
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	// Key 3
				};

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

// Function that prints data from the server
void printData(char* data, int len) {
  
  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and 
  // includes the HTTP header. 
  Serial.print("printData was called\n");   
  
  for(int i=0; i<len; i++){
    Serial.print(data[i]);
  }
  
//  while (len-- > 0) {
//    Serial.print(*(data++));
//  } 

  Serial.print("Did printData retrieve weather data above this sentence?\n"); 
}


// IP Address for www.weather.gov  
uint8 ip[] = {140,90,113,200};

// A request that gets the latest METAR weather data for LAX
GETrequest getWeather(ip, 80, "www.weather.gov", "/data/METAR/KLAX.1.txt");

void setup() {

  // Enable Serial output and ask WiServer to generate log messages (optional)
  Serial.begin(9600);
    
  // Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages) 

  Serial.print("Initiating WiServer\n"); 
  WiServer.init(NULL);  
  WiServer.enableVerboseMode(true); 
  Serial.print("WiServer initiated. \n");  
  
  // Have the processData function called when data is returned by the server
 
  getWeather.setReturnFunc(printData);
}


// Time (in millis) when the data should be retrieved 
long updateTime = 0;  //1000 millis = 1 second
int counter = 1;
    
void loop(){
    
  // Check if it's time to get an update
    if (millis() >= updateTime) {
        getWeather.submit();    
      // Get another update one hour from now
      //updateTime += 1000 * 60 * 60;
      // Get another update 30 seconds from now
        updateTime += 1000 * 30;
      Serial.print("Loop #");
      Serial.print (counter);
      Serial.print (" complete.\n");
      counter = counter + 1;
    }
 
  // Run WiServer
  WiServer.server_task();
  
  delay(10);
}

The next thing to do is print the value of len in printData(). Perhaps there is no data being returned.

The WiServer class uses asynchronous communication. That's why you register a function to be called when a reply is received.

If it were using synchronous communication, the submit() function would block until there was data, which it would return to you.

Again Paul, you were right! I keep seeing in the serial monitor “The value of len is: 0”.

Does this mean I’m not even connecting to the wireless router properly? How can I test this?

The code I used for the printData function was been changed below to display the value of len:

// Function that prints data from the server
void printData(char* data, int len) {
  
  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and 
  // includes the HTTP header. 
  Serial.print("printData was called\n");   
  
  for(int i=0; i<len; i++){
    Serial.print(data[i]);
  }
 
 Serial.print("The value of len is: ");
  Serial.print(len);
  Serial.print("\n");  
 
  Serial.print("Did printData retrieve weather data above this sentence?\n"); 
}

Does this mean I'm not even connecting to the wireless router properly? How can I test this?

I pointed out a few things I'd do for debugging purposes to isolate the problem. That is as much as I can help you with, since I've never used a WiFi shield.

I did check that the data you are sending does lead to valid data, IF the WiServer class assembles the pieces in the same way I did.

Having enabled verbose mode, I'd really expect more output from the WiServer class itself.

Ok Paul I understand, I do appreciate the help you've given me thus far as it narrowed down the problem to not receiving any data. I will continue to scour the forums and Google for relevant posts that may help me further troubleshoot the problem. Thank you!

How long is your wep key? When I was struggling with getting this shield working, I had to make a tweak to the library to set the length. IIRC, it was in g2100.c (approximate name). Search for wep_keys and there's a routine that sets the length of the key. The library sets it to 13, mine needed to be 5. Of course, I was trying all sorts of things at the time to get it to work, so this may have been a fix by coincidence.

The other thing I found, which I have commented on in serveral posts here, was that there is a 400 character packet buffer used by the library. If you receive larger packets than this, it can cause a buffer overrun and crash the Arduino. It didn't stop simple examples from working such as the weather example, but eventually, something would go wrong. I made a fairly dirty hack to just throw away large packets. In my case, since they were simply broadcasts from my ISP, the arduino really didn't care about missing them YMMV. I can post the altered version of the relevant library file this evening.

Hi wildbill! Thanks for posting. I trust you got my PM about the shields?

As for my WEP key…it’s 10 numbers…like 1234567890.

This 400 character packet buffer and buffer overrun you speak of…how can I test for this potential problem? I look forward to your reply later whenever you have time, as I’ve been frustrated ever since I got my ASync shield trying to get this SimpleClient.pde to work! :drooling_face:

Here’s the hacked g2100.c I used to drop big packets. It’s not optimal by any means, but it worked to get rid of the Verizon packets that were crashing things:

g2100.c (14.7 KB)

I ran your code from reply #4 with my tweaked library and adjusted for my SSID and wep_key. It grabs weather data as expected. One thing I do recall though is that I bought another wishield at one point and couldn't get it to work, although that may simply have been because I was running a DS18B20 of competing pins. Turned out that the jumpers weren't set the same as my first one. If my eyesight is correct the one I just used has intx set to d2, tfsh_ss_n set to d7 and LED_OFF pins connected. Good luck.

Hi WildBill,

Can you post your header file for g2100.c (g2100.h) as well?

I got the following errors when compiling:
D:\Arduino\libraries\WiShield\g2100.c: In function 'zg_process_isr':
D:\Arduino\libraries\WiShield\g2100.c:264: error: 'ZG_MAC_TYPE_ERROR' undeclared (first use in this function)
D:\Arduino\libraries\WiShield\g2100.c:264: error: (Each undeclared identifier is reported only once
D:\Arduino\libraries\WiShield\g2100.c:264: error: for each function it appears in.)
D:\Arduino\libraries\WiShield\g2100.c: In function 'zg_drv_process':
D:\Arduino\libraries\WiShield\g2100.c:487: error: 'ZG_MAC_TYPE_ERROR' undeclared (first use in this function)

oops. I hope that’s everything:

g2100.h (11.4 KB)

Well it took me nearly 2 weeks but I've finally gotten my WiShield 2.0 to work! And it is AWESOME!

Thanks for your help WildBill. Your uploads and posts helped me to troubleshoot my problem. I had to play around with my WEP settings (64 bit vs. 128 bit, keylen 5 vs. 13) to get it to work.

Glad to hear you finally cracked it; sounds like we both went through the same discovery process.