Moving function gets errors resolved but I do not understand why.

Hello,

I am working on a project and using an Instructable and there code as a guide and I get the following compiling errors.

Arduino: 1.6.6 (Mac OS X), Board: "Adafruit HUZZAH ESP8266, 80 MHz, Serial, 115200, 4M (3M SPIFFS)"

/Users/Bilsma/Documents/Arduino/StepperWebServer/StepperWebServer.ino: In function 'void setup()':
StepperWebServer:75: error: 'blink' was not declared in this scope
blink();
^
/Users/Bilsma/Documents/Arduino/StepperWebServer/StepperWebServer.ino: In function 'void loop()':
StepperWebServer:108: error: 'blink' was not declared in this scope
blink();
^
StepperWebServer:112: error: 'getValue' was not declared in this scope
int rpm = getValue(req);
^
StepperWebServer:122: error: 'getValue' was not declared in this scope
int steps = getValue(req);
^
StepperWebServer:143: error: 'printUsage' was not declared in this scope
respMsg = printUsage();
^
exit status 1
'blink' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

Here is the code:

#include <ESP8266WiFi.h>
#include <Stepper.h>

// -- USER EDIT -- 
const char* ssid     = "mywifi";    // YOUR WIFI SSID
const char* password = "mypassword";    // YOUR WIFI PASSWORD 

// change this to your motor if not NEMA-17 200 step
#define STEPS 200  // Max steps for one revolution
#define RPM 60     // Max RPM
#define DELAY 1    // Delay to allow Wifi to work
// -- END --


int STBY = 5;     // GPIO 5 TB6612 Standby
int LED = 0;      // GPIO 0 (built-in LED)

// GPIO Pins for Motor Driver board
Stepper stepper(STEPS, 16, 14, 12, 13);

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);

  // prepare onboard LED
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);

  // prepare STBY GPIO and turn on Motors
  pinMode(STBY, OUTPUT);
  digitalWrite(STBY, HIGH);
  
  // Set default speed to Max (doesn't move motor)
  stepper.setSpeed(RPM);
  
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("STEPPER: Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());

  // Blink onboard LED to signify its connected
  blink();
  blink();
  blink();
  blink();
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  String respMsg = "";    // HTTP Response Message
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // Match the request 
  if (req.indexOf("/stepper/stop") != -1) {
    digitalWrite(STBY, LOW);
    respMsg = "OK: MOTORS OFF";
  } 
  else if (req.indexOf("/stepper/start") != -1) {
    digitalWrite(STBY, HIGH);
    blink();
    respMsg = "OK: MOTORS ON";
  } 
  else if (req.indexOf("/stepper/rpm") != -1) {
    int rpm = getValue(req);
    if ((rpm < 1) || (rpm > RPM)) {
      respMsg = "ERROR: rpm out of range 1 to "+ String(RPM);
    } else {
      stepper.setSpeed(rpm);
      respMsg = "OK: RPM = "+String(rpm);
    }
  }
  // This is just a simplistic method of handling + or - number steps...
  else if (req.indexOf("/stepper/steps") != -1) {
    int steps = getValue(req);
    if ((steps == 0) || (steps < 0 - STEPS) || ( steps > STEPS )) {
      respMsg = "ERROR: steps out of range ";
    } else {  
      digitalWrite(STBY, HIGH);       // Make sure motor is on
      respMsg = "OK: STEPS = "+String(steps);
      delay(DELAY); 
      if ( steps > 0) { // Forward
        for (int i=0;i<steps;i++) {   // This loop is needed to allow Wifi to not be blocked by step
          stepper.step(1);
          delay(DELAY);   
        }
      } else {         // Reverse
          for (int i=0;i>steps;i--) {   // This loop is needed to allow Wifi to not be blocked by step
            stepper.step(-1);
            delay(DELAY); 
          }  
      }
    }
  }
  else {
    respMsg = printUsage();
  }
    
  client.flush();

  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
  if (respMsg.length() > 0)
    s += respMsg;
  else
    s += "OK";
   
  s += "\n";

  // Send the response to the client
  client.print(s);
  delay(1);
  Serial.println("Client disconnected");

  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}

int getValue(String req) {
  int val_start = req.indexOf('?');
  int val_end   = req.indexOf(' ', val_start + 1);
  if (val_start == -1 || val_end == -1) {
    Serial.print("Invalid request: ");
    Serial.println(req);
    return(0);
  }
  req = req.substring(val_start + 1, val_end);
  Serial.print("Request: ");
  Serial.println(req);
   
  return(req.toInt());
}

String printUsage() {
  // Prepare the usage response
  String s = "Stepper usage:\n";
  s += "http://{ip_address}/stepper/stop\n";
  s += "http://{ip_address}/stepper/start\n";
  s += "http://{ip_address}/stepper/rpm?[1 to " + String(RPM) + "]\n";
  s += "http://{ip_address}/stepper/steps?[-" + String(STEPS) + " to " + String(STEPS) +"]\n";
  return(s);
}
void blink() {
  digitalWrite(LED, LOW);
  delay(100); 
  digitalWrite(LED, HIGH);
  delay(100);
}

I got it working after moving blink(), printUsage() and getValue() functions from the bottom of the sketch to just above the setup() function. I am just learning all this and want to understand what is going on here. From what I understand the code looks good and should work and what I did to fix it is not ideal.

Will anyone try and explain what is going on here.

Thanks!

What version of the IDE are you using? I compiled your code, as-posted, using 1.0.5 with no issues.

PaulS:
What version of the IDE are you using? I compiled your code, as-posted, using 1.0.5 with no issues.

The latest 1.6.6

I know the error states this and I am not sure if this has anything to do with it or not, but I would like to point out I am using the "Adafruit HUZZAH ESP8266" board.

Thank you.

Ordinarily, in C and C++ code you must declare all functions above where they are used. The declaration can be the full function code or it can be just a 'forward declaration' which only names the function and the types of its arguments.

The normal Arduino IDE will insert its own forward declarations so you don't have to. Maybe something in the add-on has broken that feature? If it works with forward declarations, then keep doing it that way. It's a good habit to get into, in case you ever program something that's not Arduino.

PaulS:
What version of the IDE are you using? I compiled your code, as-posted, using 1.0.5 with no issues.

The IDE "helps" you - in ways which are not really helpful.

It's a pity they ever did the the automatic prototype generation, rather than including a paragraph explaining how prototypes work.

Alas, that is a common failing of programmers with time on their hands but no interest in writing essays.

...R

MorganS:
Ordinarily, in C and C++ code you must declare all functions above where they are used. The declaration can be the full function code or it can be just a 'forward declaration' which only names the function and the types of its arguments.

The normal Arduino IDE will insert its own forward declarations so you don't have to. Maybe something in the add-on has broken that feature? If it works with forward declarations, then keep doing it that way. It's a good habit to get into, in case you ever program something that's not Arduino.

Hi Morgans,

Just so I am clear when I write a sketch for the Arduino I should create my functions before they are used so with me moving these functions where I did is actually good practice?

While I was researching this issue it appeared the sketches i looked at had the functions near the end like this sketch.

You mentioned that there maybe an add-on to the arduino IDE that may not be creating the forward declarations any idea what this add-on may be called or what verbiage I can use to search more on this issue? As you mentioned it may be good practice to declare these functions before used it appears that there are other that do not do this and it is kind of a pain to make this modification before I can compile other example code.

thanks again.

When I used to code in NEAT/3 everything had to be declared before it was used. It was a single-pass compiler, and if it didn't know about a function or variable on the first (and only) pass, then you got an error.

Also, there were no function prototypes to work around this problem by pre-declaring functions.

Thus you put the "main" code at the very end of your source file. Just before that was the functions that the main code would call. And so on, with the lowest-level functions at the start of the file.

It was good (and indeed required) practice, and also you knew therefore how to read the code. Go to the end, that is where it starts. Start looking backwards for the major functions etc.

Positionally you always knew where a function you were calling must be defined: prior to where it was called.

In Python and Ruby you also create the functions before you call them.

It's the function prototypes in C/C++ that are confusing - and you don't need them with the Arduino IDE.

...R

Except when it generates the wrong ones, or doesn't generate 1 out of 100 and people post asking what the problem is.

By "add on" I meant "Whatever Adafruit did to make the Arduino IDE work with their board." It's not a standard Arduino board that's supported by the IDE straight out of the box.

I would not expect that a simple board definition file would do this, but I haven't looked at what is required to make it work on that particular board.

My advice is to learn about function prototypes. Use that instead of reorganizing code.

Just FYI after downloading and installing version 1.5.5 IDE all these issues disappeared as well as a few others.

Thanks for all the help and support while I did some research on C and Function prototypes I did learn some stuff but still a bit over my head.

Thanks!

Simple explanation ...

Make a new tab in the IDE, call it foo.cpp. Put this in it:

#include <Arduino.h>
int bar ()
  {
  foo (42);     // <--------- the compiler does not know about 'foo' here
  }
int foo (int x)
  {
  Serial.println ("In foo");  
  }

That gives a compiler error:

foo.cpp: In function 'int bar()':
foo.cpp:4: error: 'foo' was not declared in this scope
   foo (42);
          ^
'foo' was not declared in this scope

Two solutions

1. Change the order so that foo is declared before it is used:

#include <Arduino.h>
int foo (int x)
  {
  Serial.println ("In foo");  
  }
int bar ()
  {
  foo (42);
  }

That compiles OK, because by the time foo is called, the compiler knows what sort of function it is (because it has already encountered it).

2. Make a function prototype for foo:

#include <Arduino.h>
int foo (int x);  // prototype
int bar ()
  {
  foo (42);
  }
int foo (int x)
  {
  Serial.println ("In foo");  
  }

This prototype tells the compiler (declares to the compiler) that there is, eventually, going to be a function called foo, that takes an int argument, and returns an int.

Later on we define what foo actually does.

That also compiles OK.


The Arduino IDE automatically tries to generate prototypes for you when it sees a function definition (by doing a pre-pass of the source file) to save you knowing this.

Wow Nick Thanks for taking the time to spell that out for me.

Can someone explain why the above code in the OP compiles fine with the IDE 1.6.5 but fails in 1.6.6?

Is the problem with the IDE? Or is there an issue with the Adafruit HUZZAH ESP8266 add-on not talking correctly to the 1.6.6 version of the IDE? or both?

Where is the prototype defined in my situation?

Thanks

Bilsma:
Where is the prototype defined in my situation?

  • Turn on File > Preferences > Show verbose output during: Compilation
  • Compile your sketch
  • After compiling look at the output window to find the build folder location.
  • Open the file StepperWebServer.ino.cpp that's inside of the sketch subfolder of the build folder.
  • This is the code that the Arduino IDE generated from your sketch. By looking at it you see what went wrong.

Sometimes these errors are caused by an incorrectly generated prototype but in this case the prototypes were not generated at all.

I can replicate this problem with the following simplified code:

#include <ESP8266WiFi.h>
void setup() {
  blink();
}
void loop() {}
void blink() {}

if the include is commented out it correctly produces the prototypes.

I can replicate this problem with the following simplified code

I suspect the fault is in the ESP8266WiFi header file. That file has some really strange stuff going on.