Core frequently reboots outside of loop()

I’ve written my first app, and it mostly works: it detects a change in switch state and initiates a RESTful interaction with PushingBox. But about half the time, after completing the transaction with TCPClient (and after exiting my loop() method), I observe the following sequence in the big LED:

flashing cyan (connecting to Spark Cloud)
white pulse (reset)
flashing green (connecting to WiFi)
flashing cyan (connecting to Spark Cloud)
breathing cyan (connected)

After that, it appears to be running my loop() method, but as often as not, it goes through the reset sequence when I do the next TCPClient interaction. With the debug printout, I know that it’s not dying inside my code – it appears to go through the reset after it’s left my loop() method.

And (dunno if this is expected or not) after it reboots, it appears to NOT call my setup() method. setup() appears to be called only once after downloading the firmware.

So:

  • Any idea of what’s going on?
  • Any debugging techniques for this?

Here’s the code:

//
// Prerequsites:
// - a SPST switch (I use a magnetic reed switch detect a door opening)
//   with one lead connected to A0 and the other lead connected to GND.
// - an account on http://pushingbox.com/ with two scenarios (one
//   for door opened and one for door closed)
//
// The code here drew (in part) from:
//   https://github.com/Clement87/PushingBox-for-Spark-Core

#include "application.h"

// Secret DevIDs from PushingBox.com.
const char * serverName = "api.pushingbox.com";     // PushingBox API URL
const char * DOOR_OPENED = "vXXXXXXXXXXXXXXX";      // Scenario: door opened
const char * DOOR_CLOSED = "vXXXXXXXXXXXXXXX";      // Scenario: door closed

// Connect one side of the magnetic reed switch to A0.
// Connect the other to GND.  We'll use the internal
// pull-up so A0 goes high when the switch opens.
int reed_switch = A0;

// The on-board blue LED is programmed to follow the 
// switch state.
int blue_led = D7; 

int prev_switch_state = 0;

TCPClient client;

boolean DEBUG = true;                   // set true for serial debug printouts

void setup() {
    pinMode(blue_led, OUTPUT);
    pinMode(reed_switch, INPUT_PULLUP);
    Serial.begin(9600);                 // Start the USB Serial

    delay(1000);
    RGBBlink(255,127,0);                // flash orange at startup
    prev_switch_state = digitalRead(reed_switch);

    if (DEBUG) printNetworkParameters();
}

void loop() {
    int switch_state = digitalRead(reed_switch);
    if (prev_switch_state != switch_state) {
        // if switch has changed state, send an e-mail
        prev_switch_state = switch_state;
        digitalWrite(blue_led, switch_state);
        reportState((switch_state == HIGH) ? DOOR_OPENED : DOOR_CLOSED);
        if (DEBUG) Serial.println("...back to loop");
    }
}

// Send an email via PushingBox
void reportState(const char * pushing_box_devid) {
    if (DEBUG) Serial.print("stopping...");
    client.stop();
    if (DEBUG) Serial.print("connecting...");
    if (client.connect(serverName, 80)) {
        client.print("GET /pushingbox?devid=");
        client.print(pushing_box_devid);
        client.println(" HTTP/1.1");
        client.print("Host: ");
        client.println(serverName);
        client.println("User-Agent: Spark");
        client.println();
        client.flush();
        if (DEBUG) Serial.println("sent!");
        RGBBlink(0,0,255);             // flash blue to show success

    } else {
        if (DEBUG) Serial.println("failed.");
        RGBBlink(255, 0, 0);           // flash red to show failure

    }
}

void RGBBlink(unsigned char r, unsigned char g, unsigned char b) {
    // Use the RGB led to indicate status:
    RGB.control(true);
    delay(250);
    for (int i=0; i<4; i++) {
        RGB.color(r, g, b);
        delay(250);
        RGB.color(0, 0, 0);
        delay(250);
    }
    RGB.control(false);
}

void printNetworkParameters( void ) {
    Serial.print("SSID: ");
    Serial.println(Network.SSID());
    Serial.print("Core IP: ");
    Serial.println(Network.localIP());    
    Serial.print("Gateway: ");
    Serial.println(Network.gatewayIP());
    Serial.print("Mask: ");
    Serial.println(Network.subnetMask());
    Serial.print("WiFi RSSI: ");
    Serial.println(Network.RSSI());    
}

Hi @rdpoor

Your code does not look at the responses back from pushingbox, so they just build up and up until the core runs out of room and decides to error out. It would be better if you waited for a response and then flushed it so the buffers don’t fill up.

1 Like

I tossed this into my loop():

while (client.available()) {
    char c = client.read();
    Serial.print(c);
}

Mo bettah. Many thanks.

Related question: should I re-cast reportState() as a state machine doing short steps each time? As it stands, it takes about six seconds for it to return. If I understand correctly, the Spark stack doesn’t want a user task to block inside of loop() for very long.

6 seconds should be within the acceptable constraints for loop(). The limit is either 10 or 15 seconds. If you call a delay() in there at all for more than 1 second, I believe it runs the background tasks that it needs during that delay.

2 Likes