0

I have an Arudino Uno with an Adafruit CC3000 wifi shield attached. I am trying to send multiple http requests and store the results from the GET requests. I can make and receive the requests successfully, but space on the arduino (in the buffer?) runs out when I try to store more than one of the responses.

I'm happy to store one string at a time so I figured that instead of using the arduino String class if I use a char array instead and allocate memory, I can then free the memory afterwards. That way I could use the memory as required, hopefully not cause any issues in running the rest of the code. I know this also depends on how long the incoming response is, but let's assume the response size is small enough. Feel free to shoot me down if there are flaws in my logic... (likely)

I tried variations of creating the char array without having to define the size beforehand and then using strcpy or strcat to append the new characters, but with no success.

I want to do something in the process of: create char array, fill it, use it, free it from memory.

In the past I've used this method in such a form:

char *array = new char[size_wanted];
strcpy(array,some_char_array);
strcat(array,some_other_char_array);

This of course works well when you know what size_wanted is. I don't until I read the buffer, but once I've read the buffer I've read it, so cannot read it again. Am I missing a trick here?! Is there a simpler way to do this using the Arduino String class? Am I missing the obvious or just not understanding how this works? Any ideas would be greatly appreciated. My code:

/*************************************************** 
  Adafruit CC3000 Wifi Breakout & Shield Example
 ****************************************************/
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"

// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ   2  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed

#define WLAN_SSID       "wifi"
#define WLAN_PASS       "passoword"
#define WLAN_SECURITY   WLAN_SEC_WPA2
#define IDLE_TIMEOUT_MS  3000

// What page to grab!
#define WEBSITE      "www.adafruit.com"
#define WEBPAGE      "/testwifi/index.html"

uint32_t ip;
int n = 1;
char* result;

void setup(void)
{
  Serial.begin(115200);
  Serial.println(F("Hello, CC3000!\n")); 

  Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);

  /* Initialise the module */
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin())
  {
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }

  Serial.print(F("\nAttempting to connect to ")); Serial.println(WLAN_SSID);
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }

  Serial.println(F("Connected!"));

  /* Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP())
  {
    delay(100); // ToDo: Insert a DHCP timeout!
  }  

  /* Display the IP address DNS, Gateway, etc. */
  while (! displayConnectionDetails()) {
    delay(1000);
  }

  ip = 0;
  // Try looking up the website's IP address
  Serial.print(WEBSITE); Serial.print(F(" -> "));
  while (ip == 0) {
    if (! cc3000.getHostByName(WEBSITE, &ip)) {
      Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  }

  cc3000.printIPdotsRev(ip);

  String r1, r2, r3, r4, r5;

  r1 = connect_to_webclient();
  r2 = connect_to_webclient();
  r3 = connect_to_webclient();
  r4 = connect_to_webclient();
  r5 = connect_to_webclient();
  /*
  Serial.println("RESULTS:");
  Serial.println("r1:"); Serial.println(r1);
  Serial.println("r2:"); Serial.println(r2);
  Serial.println("r3:"); Serial.println(r3);
  Serial.println("r4:"); Serial.println(r4);
  Serial.println("r5:"); Serial.println(r5); 
  */

  /* You need to make sure to clean up after yourself or the CC3000 can freak out */
  /* the next time your try to connect ... */
  Serial.println(F("\n\nDisconnecting"));
  cc3000.disconnect();

}

void loop(void)
{
 delay(1000);
}

bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;

  if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
  {
    Serial.println(F("Unable to retrieve the IP Address!\r\n"));
    return false;
  }
  else
  {
    Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
    Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
    Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
    Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
    Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
    Serial.println();
    return true;
  }
}

String connect_to_webclient() {
  /* Try connecting to the website.
     Note: HTTP/1.1 protocol is used to keep the server from closing the connection before all data is read.
  */
  Serial.print("\nConnection number: ");
  Serial.println(n);

  Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
  if (www.connected()) {
    Serial.println("Connected succeeded");
    www.fastrprint(F("GET "));
    www.fastrprint(WEBPAGE);
    www.fastrprint(F(" HTTP/1.1\r\n"));
    www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
    www.fastrprint(F("\r\n"));
    www.println();
  } else {
    Serial.println(F("Connection failed"));    
    return;
  }

  Serial.println(F("-------------------------------------"));

  /* Read data until either the connection is closed, or the idle timeout is reached. */ 
  unsigned long lastRead = millis();

  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
    while (www.available()) {
      char c = www.read();
      Serial.print(c);
      //strcat(result, c);
      lastRead = millis();
    }
  }
  www.close();
  Serial.println(F("-------------------------------------"));
  n++;
  return result;
}
dgBP
  • 1,681
  • 6
  • 27
  • 42
  • I realise I've gone on a bit in this question, but I really feel like I'm missing a trick somewhere! – dgBP Aug 30 '16 at 00:19
  • 2
    Did you check if the webserver is sending a `Content-Length` response header? If it is not, the response size is determined by either HTTP chunking (if the `Transfer-Encoding` response header includes the [`chunked`](https://tools.ietf.org/html/rfc2616#section-3.6.1) encoding) or by closing the connection. See [RFC 2616 Section 4.4 Message Length](https://tools.ietf.org/html/rfc2616#section-4.4) for the complete algorithm to determine the message size. You need to implement logic from [this pseudo code](http://stackoverflow.com/a/19211701/65863) to receive an HTTP response body correctly. – Remy Lebeau Aug 30 '16 at 00:34
  • That is very useful, thanks. I've immediately learned a lot more about html request messages. The webserver doesn't send a content-length in the header, but the transfer-encoding is set as chunked and a I realise I can read the chunk size bytes just before the message starts, so I can start there. – dgBP Aug 30 '16 at 07:35
  • the purpose of chunking is to send dynamic/live data without knowing its final size up front. Like streaming media, or even just to add compression, etc. There will likely be multiple chunks sent, and each chunk has its own size separate from other chunks.. – Remy Lebeau Aug 30 '16 at 09:33
  • @RemyLebeau Okay, but then for each chunk isn't the chunk size at the beginning of each chunk? For one chunk it is e.g. `5 chunk 0` (each part on new lines) so wouldn't two chunks be e.g. `6 chunk1 0 6 chunk2 0` or similar? I've never actually seen multiple chunks in what I am doing although I of course won't discount it now that you have said this. – dgBP Aug 30 '16 at 12:13
  • the `0` does not appear until the very last chunk to signal the end of the message. But yes, each chuck will report its own size, and there is no guarantee that multiple chunks will have the same size. – Remy Lebeau Aug 30 '16 at 16:01

0 Answers0