Difference between Flashing and Rebooting/Resetting

I have a situation where when I Flash the Photon, it re-starts and all works ok. However, if I power it down (unplug the USB) and then power it back on, the Photon goes into SOS mode.

I’ve repeated this numerous times with the same result. I’m not changing the code. So when I want to recover from the SOS mode, and bring the Photon into Safe Mode (blinking magenta) and re-flash, again, it works ok. Unplug and plug back in, it goes into SOS mode.

So, what’s different when it reboots after flashing versus Power up?

@shiv, rebooting via flashing uses a software reset instruction of the STM32 whereas removing and reapplying the power creates a hardware reset. In software reset, retained variables, EEPROM and possible other items are preserved. You may want to look at your startup code to make sure this doesn’t create an unhandled condition creating the SOS.

2 Likes

@peekay123, thank you for your response.

What variables are these? Global?
I think I found the problem. It was related to a null reference. But that should have been the case irrespective. The only think I can think of from what you mentioned, is that global variables are retained.

Not just any global variable, retained variables are ones that you have marked with the “retained” keyword. You also need to specifically enable that feature.

 System.enableFeature(FEATURE_RETAINED_MEMORY);

 retained int someVariable;

The reference is here in the docs.

1 Like

@Ric, thank you for the clarification and the link.

@Ric, @peekay123,
Just to be clear. I only see the issue when I power down and then back up. Never when I flash the Photon. I’m also not using any retained variables. So I still can’t explain the reason for the problem.

Essentially in one of my classes, I create an instance of a contained (composition) class in the constructor or the parent. Then in various methods I call methods of the composited class. In order to get this to work. I DON’T create an instance of the composited class in the constructor, but rather in every method call I check to see if the member is nullptr. IF it is, I then create an instance. None of this makes sense to me.:confused:

What happens if, after flashing and getting it to work, you press the reset button? Does it work after that?

Showing your class would help :wink:

There are several things that run differently compared warm start to cold start.

2 Likes

Yes, it does. The only time I see different behavior is when I power cycle.

Yes, of course. Feel free to make C++ related best/better practice recommendations as well.

#ifndef NetworkConnectionManager_h
#define NetworkConnectionManager_h
#include <MQTT.h>
#include <memory>

class NetworkConnectionManager {
public:
  NetworkConnectionManager(const char *mqttBrokerUrl,
                           const char *commandSubscribeTopic,
                           const char *eventSubscribeTopic,
                           void (*messageReceivedCallback)(char *, uint8_t *,
                                                           unsigned int));
  ~NetworkConnectionManager();
  void loop();
  void ensureMqttBrokerConnectivity();
  bool publish(const char *topic, const uint8_t *payload, unsigned int plength,
               bool retain, MQTT::EMQTT_QOS qos);  

private:
  std::unique_ptr<MQTT> m_mqttClient = nullptr;
  const char *m_mqttBrokerUrl = nullptr;
  const char *m_commandSubscribeTopic = nullptr;
  const char *m_eventSubscribeTopic = nullptr;
  int m_ConnectionAttempts = 0;
  std::unique_ptr<MQTT> createMqttClient();
  void (*m_messageReceivedCallback)(char *, uint8_t *, unsigned int);
};

#endif

#include "NetworkConnectionManager.h"

NetworkConnectionManager::NetworkConnectionManager(
    const char *mqttBrokerUrl, const char *commandSubscribeTopic,
    const char *eventSubscribeTopic,
    void (*messageReceivedCallback)(char *, uint8_t *, unsigned int)) {
  m_mqttBrokerUrl = mqttBrokerUrl;
  m_commandSubscribeTopic = commandSubscribeTopic;
  m_eventSubscribeTopic = eventSubscribeTopic;
  m_messageReceivedCallback = messageReceivedCallback;
}

NetworkConnectionManager::~NetworkConnectionManager() {}

std::unique_ptr<MQTT> NetworkConnectionManager::createMqttClient() {
  return std::unique_ptr<MQTT>(
      new MQTT((char *)m_mqttBrokerUrl, 1883, m_messageReceivedCallback));
}

void NetworkConnectionManager::loop() {
  if (m_mqttClient == nullptr) {
    m_mqttClient = createMqttClient();
  }

  if (!m_mqttClient->loop()) {
    ensureMqttBrokerConnectivity();
  }
}

bool NetworkConnectionManager::publish(const char *topic,
                                       const uint8_t *payload,
                                       unsigned int plength, bool retain,
                                       MQTT::EMQTT_QOS qos) {
  if (m_mqttClient == nullptr) {
    m_mqttClient = createMqttClient();
  }

  return m_mqttClient->publish(topic, payload, plength, retain, qos);
}

void NetworkConnectionManager::ensureMqttBrokerConnectivity() {
  while (!WiFi.ready()) {
    Serial.println("Connecting to WiFi...");
    delay(300);
  }

  Serial.println("Connected to WiFi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  if (m_mqttClient == nullptr) {
    m_mqttClient = createMqttClient();
  }

  if (m_mqttClient->isConnected()) {
    return;
  }

  uint8_t noOfRetries = 5;
  uint8_t noOfRetryAttepmts = 0;

  while (!m_mqttClient->isConnected() && noOfRetryAttepmts < noOfRetries) {
    Serial.println("\rMQTT Client Not Connected");

    byte mac[6];
    WiFi.macAddress(mac);
    char clientId[18];
    sprintf(clientId, "%02x%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2],
            mac[3], mac[4], mac[5], random(0xffff));
    Serial.print("ClientId: ");
    Serial.println(clientId);

    Serial.print("Connecting to MQTT Broker: ");
    Serial.println(m_mqttBrokerUrl);
    if (m_mqttClient->connect(clientId)) {
      Serial.println("\rConnected to MQTT Broker");

      m_mqttClient->subscribe(m_commandSubscribeTopic);
      m_mqttClient->subscribe(m_eventSubscribeTopic);

      Serial.print("Subscribed to Command Topic: ");
      Serial.println(m_commandSubscribeTopic);
      Serial.print("Subscribed to Event Topic: ");
      Serial.println(m_eventSubscribeTopic);
      Serial.println("");
    } else {
      Serial.print("Failed to connect to MQTT Broker: ");
      Serial.println(noOfRetryAttepmts + 1);
      Serial.println("Creating a new instance of Mqtt Client");
      m_mqttClient = createMqttClient();
      Serial.println("Trying again in 5 seconds...");
      delay(5000);
      Particle.process();
      noOfRetryAttepmts++;
    }
  }

  if (noOfRetryAttepmts == noOfRetries) {
    Serial.println("MQTT Broker Connection Re-Try attempts exceeded...");
    Serial.println("System Resetting");
    System.reset();
  }
}

Essentially. is I create an instance of the m_mqttClient member in the constructor, rather than checking to see if is nullptr (like I’m doing say in the loop() method and others, the Photon goes into SOS mode at some point when execution tries to access the m_mqttClient member. Not at first access however, but at some point.

For example, I’ll see the following Serial.println() statements in the serial monitor.

Connected to Wifi
IP Address: 192.168.1.9
MQTT Client Not Connected
ClientId: 6c0b84ca38224c7f
Connecting to MQTT Broker: iot.eclipse.org

So it figures out that the mqttClient is not connected (no access violation here). But then as soon as it attempts to execute the next line. if (m_mqttClient->connect(clientId)) {
Bam! SOS.

Using additional Serial.println() statements scattered all over the place. I see that the m_mqttClient member is created only once (it is nullptr only once). So I don’t understand the difference in behavior.

Are you sure this is the offending line?
The actual output of Serial.print() is happening asynchronous to your code, so your code may even make it a bit further than the prunt statement before it freaks out.
Adding some delays after the print statements will help that.

Hmm… I didn’t know that. I’ll try with delays added.

Ok, so I put in a bunch of delays afte revery group of Serial.println() calls. Specifically, here is what the code looks like

  while (!m_mqttClient->isConnected() && noOfRetryAttepmts < noOfRetries) {
    Serial.println("\rMQTT Client Not Connected");

    byte mac[6];
    WiFi.macAddress(mac);
    char clientId[18];
    sprintf(clientId, "%02x%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2],
            mac[3], mac[4], mac[5], random(0xffff));
    Serial.print("ClientId: ");
    Serial.println(clientId);

    Serial.print("Connecting to MQTT Broker: ");
    Serial.println(m_mqttBrokerUrl);
    Serial.println((m_mqttClient == nullptr ? "m_mqttClient == nullptr"
                                            : "m_mqttClient != nullptr"));
    delay(5000);
    if (m_mqttClient->connect(clientId)) {
      Serial.println("\rConnected to MQTT Broker");
      delay(1000);

      m_mqttClient->subscribe(m_commandSubscribeTopic);
      m_mqttClient->subscribe(m_eventSubscribeTopic);

      Serial.print("Subscribed to Command Topic: ");
      Serial.println(m_commandSubscribeTopic);
      Serial.print("Subscribed to Event Topic: ");
      Serial.println(m_eventSubscribeTopic);
      Serial.println("");
      delay(1000);
    } else {
      Serial.print("Failed to connect to MQTT Broker: ");
      Serial.println(noOfRetryAttepmts + 1);
      Serial.println("Creating a new instance of Mqtt Client");
      delay(1000);
      m_mqttClient = createMqttClient();
      Serial.println("Trying again in 2 seconds...");
      delay(2000);
      Particle.process();
      noOfRetryAttepmts++;
    }
  }

Notice the 5 seconds delay (I started with 1 second initially). Just before the point it which it fails, but sadly, no dice. Same issues. Here is what I saw in the serial monitor.

 Connected to Wifi
 IP Address: 192.168.1.9
 MQTT Client Not Connected
 ClientId: 6c0b84ca38224c7f
 Connecting to MQTT Broker: iot.eclipse.org
 m_mqttClient != nullptr

Next I tried creating a new instance just before the call to connect (irrespective of the nullptr result earlier). The code looks like this:

    Serial.print("Connecting to MQTT Broker: ");
    Serial.println(m_mqttBrokerUrl);
    Serial.println((m_mqttClient == nullptr ? "m_mqttClient == nullptr"
                                            : "m_mqttClient != nullptr"));
    delay(1000);
    m_mqttClient = createMqttClient();
    delay(5000);
    if (m_mqttClient->connect(clientId)) {
      Serial.println("\rConnected to MQTT Broker");
      delay(1000);

I don’t get an SOS now. But the MQTT Client never connects even after re-trying 5 times. Then as per the logic, the Photon is restarted. And then lather rinse, repeat. Can’t explain why the MQTT Client can’t/won’t connect either now :confounded:

This is outside my area of direct experience but lots of things online say that you should not do this test this way. A better way is supposed to be:

if (m_mqttClient) {
   m_mqttClient = createMqttClient();
}

Can you try that?

@bko, thank you for your response.

The code is question is actually what works. That is, if I create the instance in the constructor (rather than delayed instantiation), then I have an issue. However, if I don’t create the instance in the constructor (The code I pasted does not create an instance in the constructor), but rather, check to see if it is nullptr and only create if nullptr, then it works.

The code you showed, may be the correct/better way to check for nullptr, but that’s not the cause of the issue.

1 Like

Yes, it seems this is the C++ way to test, except this tests for if not null. If I were to use this to test for nullptr it would be a negative test like so:

if (!m_mqttClient) {}

Not sure of the benefit of doing this. Personally, I don’t like to use a negative test in these cases. But that’s just me :pensive: