Variables declared in while loop not available upon exit?

Hi,

I'm trying to do some flow control and have what's probably a very basic problem.

I'm syncing nodes on an esp-now network to sleep at 10 minute intervals. The master node determines the time needed to sleep and pushes this info to the nodes. I have had an issue where after sleeping, the master wakes slightly early. Rather than going back to sleep for a short period (less than a second usually) I want the master to wait until the coms window is open then contact nodes.

In the setup funciton, I'm tryng to write a while loop that will determine whether it's time to take action. If it's not, it should recalculate seconds since midnight and time to sleep untill there is 1 second left until the comms window is open, then continue.. The trouble I'm having is that the variables that are being declared in the while loop aren't available for downstream action after the loop exit, so the compiler is complaining with a "variable x not declared in scope" error. I wanted to avoid using globals for these so just wondering what the right approach is here or what I'm doing wrong.

Thanks in advance.

Code below..


#include <WiFi.h>
#include <esp_now.h>
#include <ThreeWire.h>
#include <RtcDS1302.h>


#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
int TIME_TO_SLEEP ;          /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

int poll_times[6] = {21600, 32400, 43200, 54000, 64800, 75600};
int poll_hrs[6] = {6, 9, 12, 15, 18, 21};
int poll_pos = 0;
int task; // node instruction

//RTC stuff
ThreeWire myWire(4, 5, 2); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);
#define countof(a) (sizeof(a) / sizeof(a[0]))

typedef struct dataOut_struct {
  int x; // task: 0 = sleep, 1 = post
  int y; // time2sleep
} dataOut_struct;
dataOut_struct dataOut;

typedef struct dataIn_struct {
  int x; // ID of node
  int y; // datapoint
  int z; // battery
} dataIn_struct;
dataIn_struct dataIn;

void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength) {
  snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}

void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int len) {
  dataIn_struct* dataIn = (dataIn_struct*) data;
  // format the mac address
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  // debug log the message to the serial port
  Serial.println(macStr);
  Serial.println(dataIn->x);
  Serial.println(dataIn->y);
  Serial.println(dataIn->z);
}

// callback when data is sent
void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status) {
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  Serial.print("Last Packet Sent to: ");
  Serial.println(macStr);
  Serial.print("Last Packet Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void broadcast() {
  // this will broadcast a message to everyone in range
  uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
  if (!esp_now_is_peer_exist(broadcastAddress)) {
    esp_now_add_peer(&peerInfo);
  }
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &dataOut, sizeof(dataOut_struct));

  if (result == ESP_OK) {
    Serial.println("Broadcast message success");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
    Serial.println("ESPNOW not Init.");
  }
  else if (result == ESP_ERR_ESPNOW_ARG) {
    Serial.println("Invalid Argument");
  }
  else if (result == ESP_ERR_ESPNOW_INTERNAL) {
    Serial.println("Internal Error");
  }
  else if (result == ESP_ERR_ESPNOW_NO_MEM) {
    Serial.println("ESP_ERR_ESPNOW_NO_MEM");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
    Serial.println("Peer not found.");
  }
  else {
    Serial.println("Unknown error");
  }
}

void espnow_up() {
  WiFi.mode(WIFI_STA);
  Serial.println("ESPNow Example");
  // Output my MAC address - useful for later
  Serial.print("My MAC Address is: ");
  Serial.println(WiFi.macAddress());
  // shut down wifi
  WiFi.disconnect();
  // startup ESP Now
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
    esp_now_register_recv_cb(receiveCallback);
    esp_now_register_send_cb(sentCallback);
  }
  else {
    Serial.println("ESPNow Init Failed");
    delay(3000);
    ESP.restart();
  }
}



void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

void printDateTime(const RtcDateTime& dt)
{
  char datestring[20];

  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(),
             dt.Day(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second() );
  Serial.print(datestring);
}



int get_ssm(const RtcDateTime& dt) {
  char datestring[20];
  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(),
             dt.Day(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second() );

  Serial.println("Trying to get hrs, mins, sec for ssm calcs");
  int cur_hr = dt.Hour();
  int cur_min = dt.Minute();
  int cur_sec = dt.Second();
  int ssm = (cur_hr * 3600L) + (cur_min * 60L) + cur_sec;
  Serial.print("Calculated seconds since midnight: "); Serial.println(ssm);
  return ssm;
}

void pollpos(int s) {
  Serial.print("int passed to pollpos: "); Serial.println(s);
  Serial.println("Parsing poll_times to see where we are at");
  // if after 9pm, do nothing
  Serial.println(poll_times[5] + 30);
  if (s > (poll_times[sizeof(poll_times) - 1] + 30)) {
    Serial.println("--------- test conditional past 9 pm ---------");
    Serial.println("It's past 9pm. No need to do anything till morning.");
    // define task as sleep
    task = 0;
    return;
  }
  else { //figure out where we are in the poll times
    for (int i = 0; i < 6; i++) {
      if (s > poll_times[i] + 30) { // if we are 30 seconds past polling time..
        Serial.print("poll_time being queried: "); Serial.print(poll_hrs[i]);
        Serial.print(":00 hrs  -   ");
        Serial.println("moving on. Not our window");
      }
      else if (s < poll_times[i] - 30) { // if ssm is less than 30 seconds before polling time..
        Serial.print("poll_time being queried: "); Serial.print(poll_hrs[i]);
        Serial.print(":00 hrs  -   ");
        Serial.println("We are within the current window");
        task = 0;
        return;
      }
      else if (s > poll_times[i] - 30 && s < poll_times[i] + 30) {
        Serial.print("poll_time being queried: "); Serial.print(poll_hrs[i]);
        Serial.print(":00 hrs  -   ");
        Serial.println("We are within the reporting window!");
        Serial.println("+++++ POLL NODES +++++");
        task = 1;
        return;
      }
    }
  }
}





void setup() {
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  Rtc.Begin();
  RtcDateTime now = Rtc.GetDateTime();
  printDateTime(now);

  // wait untill there is 1 second left to coms window, then move on.
  boolean coms_window = false;
  while (!coms_window) {
    int ssm = get_ssm(now); // get seconds since midnight
    long int run_start = millis(); // define start time to adjust sleep later
    int adjust_sleep = 600 - (ssm % 600); // sync sleep time to 10 minute intervals.
    if (adjust_sleep < 2) {
      coms_window = true;
    }
  }

  pollpos(ssm); // find position in poll_times array to determine instructions for nodes
  dataOut.x = task; // task: 0 = sleep, 1 = post
  dataOut.y = adjust_sleep; // sync node sleep time

  espnow_up(); // start esp-now service

  broadcast(); // send task instruction and sleep time to nodes
  //listen for reply from nodes for 5 seconds
  long int listen_start = millis();
  Serial.print("waiting for reply from nodes: ");
  while (millis() - listen_start < 5000) {
    delay(1000);
    Serial.println(".");
  }

  // Sleep time.
  int run_end = millis();
  TIME_TO_SLEEP = adjust_sleep - (run_end - run_start) / 1000;

  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds ");
  Serial.println("Going to sleep now");
  Serial.flush();
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop() {
  //This is not going to be called
}

The programming language is designed to do that. Variables declared in loop() or any other function, or within a code block are local, and "disappear" upon exit from the function or code block.

Make the variables global if you want other routines to see them. Or, copy the values to global variables, call a function with the values in the argument list, etc.

1 Like

Ok thanks, I'll use globals then.

If you declare them at the beginning of setup(), they will be available everywhere within setup(), including the while looop.

Thanks mate

Variable scope is an important concept. A tutorial on scope.

1 Like

There's a world of scope between your "disappearing" very local variable in the while statement body and full on global.

google

 scope in c++

and read until your eyes aren't glazed over, it's fairly simple conceptually, at least, just needs good 'splainin', different ppl will find different approaches better so shop around a bit if nothing later here adds to your undestanding.

Haha. First take that link @groundFungus tossed, at least.

Contrast with

https://c-for-dummies.com/blog/?p=5204

a7

1 Like

Do you mean "beginning" or "before" setup()? I've not tested it but I was under the belief that setup() was just another function.

Read it carefully. He is talking about a while loop within setup(), not the main loop().
I was also going to respond as you had and had to read it twice.

Thanks, Its easy for me to scan through and sometimes not fully absorb the posts. Although some posts are not written to be fully absorbed :slight_smile:

This compiles. The r if defined in the while loop will result in an error. Yet in the below it is not a global as it will disappear when setup is complete.

void setup() {
  Serial.begin(9600);
int i;
int r;
  while(i<1000){
      r = 5;
  }
  Serial.print(r);
}
void loop() {
  // put your main code here, to run repeatedly:
}

thanks for all your replies and pointing to some relevant docs.

Yep plenty of reading to do as always..

Mat

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.