Pages: [1]   Go Down
Author Topic: WiFly module delays loop while retrieving data  (Read 1058 times)
0 Members and 1 Guest are viewing this topic.
Milan - Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello everyone,
I am working with a RN171 module that adds Wi-Fi connectivity to an Arduino UNO board.
Everything works fine, and I can use the WiFlyHQ library (https://github.com/harlequin-tech/WiFlyHQ) to connect to a server using wifly.open() and then some wifly.println() instructions to build a GET request.
The problem I am having now is that the loop is paused while the module fetches the response from the server (like when using a delay() instruction). I am quite sure the pause happens while fetching the response and not while parsing the incoming serial data because I made some prints to the serial monitor reading millis() between functions.
This can be a problem because it interferes with other code running on the loop (for example the fading of some LEDs): is there a way to avoid this delay and keep the loop stable? Any suggestions?

Thank you for the help...
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 642
Posts: 50367
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
is there a way to avoid this delay and keep the loop stable? Any suggestions?
Probably not. Client/server communication is not asynchronous. That is, when you make the request, you don't come around later to see if a response has arrived. You wait for it.

Post your code, though, so we can be sure.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can you post a snippet of your code? That may help others debug your issue faster.

I've been working with the WiFly the past few days and I've also looked through the WiFlyHQ code. However I haven't gotten as far as you.

But I looked at the WiFly::read function you referred to. The function looks like it fetches 1 character per iteration of the loop, except on the case where it reads an asterisk character. Then it checks if the TCP connection is still open.

So maybe the delay you are experiencing is happening there. You mentioned a GET request, so that must mean you are using HTTP. I could be wrong, but I think HTTP closes its connection when it is finished with a request.

I'm not quite sure how you would get around this issue. But if you want to look into it more, look at the "checkStream" function. This is where the delay happens.
Logged

Milan - Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for the answers!
After the WiFly initialization on the setup() function like on the library examples, the loop() contains this quite simple snippet to make a new request every 30 seconds:

Code:
void loop() {
    time = millis();
    ....
    ....
    if ((time - prevTime) > 30000) { // update every 30 seconds
        updateURL();
        prevTime = time;
    }
    ....
    ....
}

And here is the updateURL() function that makes the request:

Code:
boolean updateURL() {
  if (wifly.open("www.theurl.com", 80)) {
    Serial.println("Connected, sending request...");
    /* Send the request */
    wifly.println(F("GET /file.php HTTP/1.1"));
    wifly.println(F("Host: www.theurl.com"));
    // wifly.println(F("Connection: close"));
    wifly.println();
    Serial.println("Waiting results...");
    return true;
  }
  else {
    Serial.println("Connection failed");
    return false;
  }
}

In this way I am sending the HTTP request (is there a faster/lighter method?) to read a page on the server.
All other instructions on the loop rely on the time variable, so everything is non-blocking.

On the loop() I am also reading back from the buffer of the WiFly serial connection one char per loop (so this is non-blocking too), using some "if" statements to skip the HTTP headers and find the real value: this is not very elegant, but works just fine without complex string parsing etc: I am finding the sequence {"pattern": " to skip all other content. :-D

Code:
if (wifly.available()) {
    reading = wifly.read();
    if ((reading == '{') and (count == 0)) {
      count ++;
    } else if ((reading == '"') and (count == 1))
      count ++;
    } else if ((reading == 'p') and (count == 2))
      count ++;
    } else if ((reading == 'a') and (count == 3))
      count ++;
    } else if ((reading == 't') and (count == 4))
      count ++;
    } else if ((reading == 't') and (count == 5))
      count ++;
    } else if ((reading == 'e') and (count == 6))
      count ++;
    } else if ((reading == 'r') and (count == 7))
      count ++;
    } else if ((reading == 'n') and (count == 8))
      count ++;
    } else if ((reading == '"') and (count == 9)) {
      count ++;
    } else if ((reading == ':') and (count == 10)) {
      count ++;
    } else if ((reading == ' ') and (count == 11)) {
      count ++;
    } else if ((reading == '"') and (count == 12)) {
      count ++;
    } else {
      count = 0;
    }
    if (count == 13) {
      pattern = wifly.read();
      Serial.print("pattern: ");
      Serial.println(pattern);
    }
  }

I agree, probably there is no way to avoid that delay, but maybe someone more expert than me can suggest a better approach...
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 642
Posts: 50367
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
And here is the updateURL() function that makes the request:
Printing millis() to the serial port before and after the open call would tell you how long that takes.

Printing millis() again after sending the request would tell you how long that took.

Which is the time-consuming part of the code? If that is an atomic operation, like open(), it really can't be sped up.
Logged

Milan - Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I printed the millis() and it's the open() operation that is time-consuming. It usually takes an average of 600 millis (sometimes more) while the other parts of the instructions stay below 50-60 millis.
Gohn, I'll try to take a look at the functions inside the library to better understand the issue...

By the way, is there another way to avoid the problem? Maybe something more hardware-oriented? I am using a TLC5940 to drive some small LEDs in different ways, according to the reply of the server. So I'm thinking about something like an external "buffer" chip between the Arduino and the TLC5940 that keeps some instructions and constantly pushes them to the TLC5940 even when the Arduino is busy. Or maybe another "buffer" chip between the Arduino and the WiFi module. Is this a stupid or complex idea? Any suggestions?

Thank you again!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe you can use TCP, since that will give you a constant connection. There would be no need to keep reconnecting.

If you are getting data from a source you do not control, you could write a TCP server that grabs the data from that website and sends it your Arduino.

That way you only have to call open once. Although I'm not sure what happens in the case of disconnects.
Logged

Milan - Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Good approach gohn, I already experimented something similar with cron etc, but this is another path, cool. I will explore this, but first I have to find a hosting that allows TCP sockets, I prefer not to do this relying on a local setup...

Thanks!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah, I don't know of any free hosts that allow TCP sockets.

But Pusher allows WebSockets for free -> http://pusher.com/pricing

The WiFlyHQ lib has an example using WebSockets.

----------

So with the CRON are you using your WiFly as the HTTP server? That's a good idea. I would assume there would be no blocking in this case. How did that work for you?
Logged

Milan - Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I stopped with the CRON approach because it means dealing with port forwarding, dynamic IPs and so on. Quite simple to set up, but I preferred something more independent from the LAN environment: making requests as a client allows to only edit SSID and password on the sketch when changing WiFi network.

I saw the WebSocket example, and it seems a good solution. I made some experiments with Twitter stream APIs, but that was a bit too complex to manage. Thank you for pointing me to Pusher, free services are always welcome. :-)
Logged

Milan - Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow... the Pusher service is really simple to setup and use, cool. I made some tests and it works fine!
The main problem is that at a certain point the socket is closed, because the sketch becomes unresponsive. I need to understand why... Any suggestions?
I think that my sketch is pushing the processor's limits: I don't know if it can bear both the WiFly and the LED animations with the TLC5940. I have to understand how to optimize the code.

Thanks again!
Logged

Pages: [1]   Go Up
Jump to: