HTTP Client Memory Management Problem

I’m getting an SOS error on my current application, referencing a Memory Manager issue. SOS, three flashes, SOS.

My application runs the HTTPClient Library to download trains times as a small string of numbers (twice) and then display those numbers via some WS2812’s. It runs properly and does everything it needs to do. However, when it goes to run again (after a 20 second delay), I get the Memory Manager issue and I can see the device restart itself.

See code below:

// This #include statement was automatically added by the Particle IDE.
#include "neopixel/neopixel.h"
#include "application.h"
#include "HttpClient/HttpClient.h"

/**
* Declaring the variables.
*/
unsigned int nextTime = 0;    // Next time to contact the server
HttpClient http;

// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
    //  { "Content-Type", "application/json" },
    //  { "Accept" , "application/json" },
    { "Accept" , "*/*"},
    { NULL, NULL } // NOTE: Always terminate headers with NULL
};

http_request_t request;
http_response_t response;

SYSTEM_MODE(AUTOMATIC);

#define PIXEL_PIN D3
#define PIXEL_PIN2 D2
#define PIXEL_COUNT 8
#define PIXEL_TYPE WS2812B

Adafruit_NeoPixel north = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
Adafruit_NeoPixel south = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN2, PIXEL_TYPE);

void setup() 
{
  north.begin();
  north.show(); // Initialize all pixels to 'off'
  north.setPixelColor(0, 0, 0, 0);
  north.setBrightness(180);
  north.show();
  
  south.begin();
  south.show(); // Initialize all pixels to 'off'
  south.setPixelColor(0, 0, 0, 0);
  south.setBrightness(180);
  south.show();
}

void loop() {
    if (nextTime > millis()) {
        return;
    }
    
    //30273 - Addison Red North
    //30274 - Addison Red South
    //30071 - Southport Brown South
    //30070 - Southport Brown North
    // Set up or url path
    
   downloadSet(north, "30273");
   downloadSet(south, "30274");
    
    
    //repeat again in 20 seconds
    nextTime = millis() + 20000;
}

void downloadSet(Adafruit_NeoPixel strip, String t) {
    //s == strip
    //t = trip
    request.hostname = "www.johnventions.com";
    request.port = 80;
    request.path = "/trains/trains.php?trip=" + t;

    // Get request for train times
    http.get(request, response, headers);

    //set up a character array to copy the response to
    const int value_count = 8; // the maximum number of values
    int trains[value_count];    // store the values here
    
    char string[50]; //string to copy the response to
    strcpy(string, response.body);  // the string to split
    //strcpy(string, "2, 8, 11");
    int idx = 0;
    for (char* pt=strtok(string, " "); pt && idx<value_count; pt=strtok(NULL, " ")) {
       trains[idx++] = atoi(pt); //pt = the substring, atoi converts it to an int
    }
    
    
    //loop through and set all pixels to blue (meaning no train)
    for (int i=0; i<PIXEL_COUNT; i++) {
        strip.setPixelColor(i, 255, 255, 255);
    }
    
    strip.show();
    
    
    //set train pixels to red (meaning there is a train in that time slot)
    for (int j=0; j<idx; j++) {
        if (trains[j] && trains[j] > 9) {
            int minute = trains[j]-11;
            if (minute < 8 && minute >= 0) {
                strip.setPixelColor(minute, 255, 0, 0);
            }
        }
    }
    
    //make char array to display
    strip.show();
}

Is there a flush function or any other memory saving technique I should be running on the request or the response to save memory? I didn’t see anything in the library documentation about it.

If you are having a memory corruption issue as you suspect, then this is one obvious area to look at. Defensive code would be:

char   str[50];
strncpy(str, response.body, sizeof(str));
str[sizeof(str) - 1] = '\0';

Without control over the size of the response, it would be very easy to blow your stack away using the strcpy function.

This may, or may not, be the cause of your problem here, but get in the habit of protecting memory and these kinds of issues will be less likely to bite you.

1 Like

Thanks @Muskie - I’ll try this out tonight and let you know if it helps. I appreciate the feedback and the memory usage lesson!

Thanks again @Muskie. I incorporated your suggestion but am still having the same issue.

I’ll keep testing other options but am open to more advice if anyone has any ideas.

Ok, something else to look at would be passing the strip parameter by value. This would cause a copy to be created on the stack that might be causing problems. Try changing the declaration of the parameter to pass by reference.

void downloadSet(Adafruit_NeoPixel & strip, String t) {

I don’t know if this is related or not, but it is worth a try.

You might also want to change the original declarations of the north and south instances to avoid construct and copy:

Adafruit_NeoPixel   north(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
Adafruit_NeoPixel   south(PIXEL_COUNT, PIXEL_PIN2, PIXEL_TYPE);
1 Like

That did it! You’re a life saver, @Muskie