amperka / ino

Command line toolkit for working with Arduino hardware
http://inotool.org
MIT License
1.08k stars 233 forks source link

Preprocessor introduces compiler error #224

Closed joshpfosi closed 9 years ago

joshpfosi commented 9 years ago

Hi, new to ino here but grateful for it! Unfortunately, it seems to be introducing a compiler error in my sketch (below). I've attached the whole sketch for reproduction purposes. I simply have a new ino project with this as the only src file (sketch.ino). When I run ino build, it produces sketch.cpp (attached below) which has a clear error due to prepending function declarations to the top of the file. I ran it through cpp and this is not default behavior (obviously, but to be sure), so not sure if this is a bug with ino or my use of it! Please help, I really would like to use an enum in this way to clean things up.

By the way, running w/ Arduino Mega 2560, on Mac OS Yosemite. I've tried removing .build and rebuilding but same error.

Thanks!

#define FALSE         0
#define TRUE          1

/* pins */
#define RED_LED       6
#define BLUE_LED      4
#define GREEN_LED     8
#define PIN1          0
#define PIN2          1
#define POTPIN1       A0
#define POTPIN2       A1

/* misc */
#define ONE_SEC_DELAY 20
#define LED_ON        255
#define LED_OFF       0
#define SLEEP_DUR     15000

/* frequencies */
#define TEN_HERTZ     50
#define FOUR_HERTZ    125
#define TWO_HERTZ     250
#define ONE_HERTZ     500

/* global which tracks diagnostic errors */
int numErrors = 5;

/* contains interrupt state */
int switch1   = FALSE;
int switch2   = FALSE;

/* state computation */
enum states { ON, OFF, RUN, SLEEP, DIAG, MAX_STATES };

/* ---------- STATE FXNS ---------- */

enum states on(void) {
    digitalWrite(RED_LED, HIGH); delay(ONE_HERTZ);
    digitalWrite(RED_LED, LOW);  delay(ONE_HERTZ);

    return DIAG;
}

enum states off(void) {
    return OFF;
}

enum states run(void) {
    if (millis() > SLEEP_DUR) return SLEEP;

    float brightness = LED_ON, pot1Val = 0, pot2Val = 0;
    long prevMillisGreen = millis(), 
         prevMillisBlue = millis(), 
         currentMillis = 0;
    int fadeAmt = 5, blueLedStatus = 0, freq;

    while (1) {
        currentMillis = millis();

        pot1Val = analogRead(POTPIN1)  / 500.0;
        pot2Val = (analogRead(POTPIN2) / 1023.0) * LED_ON;

        long greenInterval = currentMillis - prevMillisGreen;

        /* flash green LED */
        if (greenInterval > 120 && brightness > 0) {
            prevMillisGreen = currentMillis;
            brightness -= fadeAmt;
            analogWrite(GREEN_LED, brightness);    
        } 
        else if (brightness <= 0) {
            if (greenInterval > 2000) {
                analogWrite(GREEN_LED, LED_OFF); return RUN;
            }
            else if (greenInterval > 1500) { analogWrite(GREEN_LED, LED_OFF); }
            else if (greenInterval > 1000) { analogWrite(GREEN_LED, LED_ON);  }
            else if (greenInterval > 500)  { analogWrite(GREEN_LED, LED_OFF); }
            else if (greenInterval > 0)    { analogWrite(GREEN_LED, LED_ON);  }
        }

        /* flash blue LED */
        long blueInterval = currentMillis - prevMillisBlue;
        freq = (switch1) ? TEN_HERTZ : ONE_HERTZ;
        freq *= pot1Val;

        if (blueInterval > freq) {
            prevMillisBlue = currentMillis;
            blueLedStatus = (blueLedStatus == 0) ? LED_ON : LED_OFF;
            analogWrite(BLUE_LED, blueLedStatus);
        }

        /* reduce brightness by number between 0 and 255 */
        if (switch2) analogWrite(RED_LED, LED_ON - pot2Val);

    }

    return RUN;
}

enum states sleep(void) {
    int i;
    for (i = 0; i < 4; ++i) {
        analogWrite(BLUE_LED, LED_ON);  delay(FOUR_HERTZ);
        analogWrite(BLUE_LED, LED_OFF); delay(FOUR_HERTZ);
    }

    int brightness = LED_ON, fadeAmt = 5; 

    // fade LED
    while (brightness > 0) {
        analogWrite(BLUE_LED, brightness);    
        brightness -= fadeAmt;
        delay(20);    
    }

    analogWrite(BLUE_LED, LED_OFF);

    return OFF;
}

enum states diag(void) {
    int i;
    for (i = 0; i < numErrors; ++i) {
        digitalWrite(RED_LED, HIGH); delay(TWO_HERTZ);
        digitalWrite(RED_LED, LOW);  delay(TWO_HERTZ);
    }

    return RUN;
}

/* ---------- ISRs ---------- */

void setSwitch1(void) { switch1 = true; }
void setSwitch2(void) { switch2 = switch1; }

/* states fxns */
enum states (* state[])(void) = { on, off, run, sleep, diag };

void setup() {
    pinMode(RED_LED,   OUTPUT);
    pinMode(BLUE_LED,  OUTPUT);
    pinMode(GREEN_LED, OUTPUT);

    pinMode(POTPIN1,   INPUT);
    pinMode(POTPIN2,   INPUT);

    attachInterrupt(PIN1, setSwitch1, RISING); // NOTE should be FALLING
    attachInterrupt(PIN2, setSwitch2, RISING);
}

enum states curState = ON;

void loop() {
    curState = state[curState]();
    if (curState != RUN) digitalWrite(RED_LED, LOW);
}
.build/mega2560/src/sketch.cpp
#include <Arduino.h>

enum states on(void);
enum states off(void);
enum states run(void);
enum states sleep(void);
enum states diag(void);
void setSwitch1(void);
void setSwitch2(void);
void setup();
void loop();
#line 1 "src/sketch.ino"
#define FALSE         0
#define TRUE          1

/* pins */
#define RED_LED       6
#define BLUE_LED      4
#define GREEN_LED     8
#define PIN1          0
#define PIN2          1
#define POTPIN1       A0
#define POTPIN2       A1

/* misc */
#define ONE_SEC_DELAY 20
#define LED_ON        255
#define LED_OFF       0
#define SLEEP_DUR     15000

/* frequencies */
#define TEN_HERTZ     50
#define FOUR_HERTZ    125
#define TWO_HERTZ     250
#define ONE_HERTZ     500

/* global which tracks diagnostic errors */
int numErrors = 5;

/* contains interrupt state */
int switch1   = FALSE;
int switch2   = FALSE;

/* state computation */
static enum states { ON, OFF, RUN, SLEEP, DIAG, MAX_STATES };

/* ---------- STATE FXNS ---------- */

enum states on(void) {
    digitalWrite(RED_LED, HIGH); delay(ONE_HERTZ);
    digitalWrite(RED_LED, LOW);  delay(ONE_HERTZ);

    return DIAG;
}

enum states off(void) {
    return OFF;
}

enum states run(void) {
    if (millis() > SLEEP_DUR) return SLEEP;

    float brightness = LED_ON, pot1Val = 0, pot2Val = 0;
    long prevMillisGreen = millis(), 
         prevMillisBlue = millis(), 
         currentMillis = 0;
    int fadeAmt = 5, blueLedStatus = 0, freq;

    while (1) {
        currentMillis = millis();

        pot1Val = analogRead(POTPIN1)  / 500.0;
        pot2Val = (analogRead(POTPIN2) / 1023.0) * LED_ON;

        long greenInterval = currentMillis - prevMillisGreen;

        /* flash green LED */
        if (greenInterval > 120 && brightness > 0) {
            prevMillisGreen = currentMillis;
            brightness -= fadeAmt;
            analogWrite(GREEN_LED, brightness);    
        } 
        else if (brightness <= 0) {
            if (greenInterval > 2000) {
                analogWrite(GREEN_LED, LED_OFF); return RUN;
            }
            else if (greenInterval > 1500) { analogWrite(GREEN_LED, LED_OFF); }
            else if (greenInterval > 1000) { analogWrite(GREEN_LED, LED_ON);  }
            else if (greenInterval > 500)  { analogWrite(GREEN_LED, LED_OFF); }
            else if (greenInterval > 0)    { analogWrite(GREEN_LED, LED_ON);  }
        }

        /* flash blue LED */
        long blueInterval = currentMillis - prevMillisBlue;
        freq = (switch1) ? TEN_HERTZ : ONE_HERTZ;
        freq *= pot1Val;

        if (blueInterval > freq) {
            prevMillisBlue = currentMillis;
            blueLedStatus = (blueLedStatus == 0) ? LED_ON : LED_OFF;
            analogWrite(BLUE_LED, blueLedStatus);
        }

        /* reduce brightness by number between 0 and 255 */
        if (switch2) analogWrite(RED_LED, LED_ON - pot2Val);

    }

    return RUN;
}

enum states sleep(void) {
    int i;
    for (i = 0; i < 4; ++i) {
        analogWrite(BLUE_LED, LED_ON);  delay(FOUR_HERTZ);
        analogWrite(BLUE_LED, LED_OFF); delay(FOUR_HERTZ);
    }

    int brightness = LED_ON, fadeAmt = 5; 

    // fade LED
    while (brightness > 0) {
        analogWrite(BLUE_LED, brightness);    
        brightness -= fadeAmt;
        delay(20);    
    }

    analogWrite(BLUE_LED, LED_OFF);

    return OFF;
}

enum states diag(void) {
    int i;
    for (i = 0; i < numErrors; ++i) {
        digitalWrite(RED_LED, HIGH); delay(TWO_HERTZ);
        digitalWrite(RED_LED, LOW);  delay(TWO_HERTZ);
    }

    return RUN;
}

/* ---------- ISRs ---------- */

void setSwitch1(void) { switch1 = true; }
void setSwitch2(void) { switch2 = switch1; }

/* states fxns */
enum states (* state[])(void) = { on, off, run, sleep, diag };

void setup() {
    pinMode(RED_LED,   OUTPUT);
    pinMode(BLUE_LED,  OUTPUT);
    pinMode(GREEN_LED, OUTPUT);

    pinMode(POTPIN1,   INPUT);
    pinMode(POTPIN2,   INPUT);

    attachInterrupt(PIN1, setSwitch1, RISING); // NOTE should be FALLING
    attachInterrupt(PIN2, setSwitch2, RISING);
}

enum states curState = ON;

void loop() {
    curState = state[curState]();
    if (curState != RUN) digitalWrite(RED_LED, LOW);
}

Ino Build Error:

src/sketch.ino
Scanning dependencies of src
src/sketch.cpp
.build/mega2560/src/sketch.cpp:3: error: use of enum 'states' without previous declaration
.build/mega2560/src/sketch.cpp:3: error: invalid type in declaration before ';' token
.build/mega2560/src/sketch.cpp:4: error: use of enum 'states' without previous declaration
.build/mega2560/src/sketch.cpp:4: error: invalid type in declaration before ';' token
.build/mega2560/src/sketch.cpp:5: error: use of enum 'states' without previous declaration
.build/mega2560/src/sketch.cpp:5: error: invalid type in declaration before ';' token
.build/mega2560/src/sketch.cpp:6: error: use of enum 'states' without previous declaration
.build/mega2560/src/sketch.cpp:6: error: invalid type in declaration before ';' token
.build/mega2560/src/sketch.cpp:7: error: use of enum 'states' without previous declaration
.build/mega2560/src/sketch.cpp:7: error: invalid type in declaration before ';' token
src/sketch.ino: In function 'states on()':
src/sketch.ino:37: error: new declaration 'states on()'
.build/mega2560/src/sketch.cpp:3: error: ambiguates old declaration 'int on()'
src/sketch.ino: In function 'states off()':
src/sketch.ino:44: error: new declaration 'states off()'
.build/mega2560/src/sketch.cpp:4: error: ambiguates old declaration 'int off()'
src/sketch.ino: In function 'states run()':
src/sketch.ino:48: error: new declaration 'states run()'
.build/mega2560/src/sketch.cpp:5: error: ambiguates old declaration 'int run()'
src/sketch.ino: In function 'states sleep()':
src/sketch.ino:100: error: new declaration 'states sleep()'
.build/mega2560/src/sketch.cpp:6: error: ambiguates old declaration 'int sleep()'
src/sketch.ino: In function 'states diag()':
src/sketch.ino:121: error: new declaration 'states diag()'
.build/mega2560/src/sketch.cpp:7: error: ambiguates old declaration 'int diag()'
src/sketch.ino: At global scope:
src/sketch.ino:137: error: invalid conversion from 'int (*)()' to 'states (*)()'
src/sketch.ino:137: error: invalid conversion from 'int (*)()' to 'states (*)()'
src/sketch.ino:137: error: invalid conversion from 'int (*)()' to 'states (*)()'
src/sketch.ino:137: error: invalid conversion from 'int (*)()' to 'states (*)()'
src/sketch.ino:137: error: invalid conversion from 'int (*)()' to 'states (*)()'
make: *** [.build/mega2560/src/sketch.o] Error 1
Make failed with code 2
nophead commented 9 years ago

I think the problem is that ino copies the behaviour of the Arduino IDE and inserts function prototypes at the top. This won't work if the functions use a type declared in the sketch. I think the solution is to define the enum in a header file and include that at the top. Hopefully the prototypes are inserted below the headers.

BTW in C++ states becomes a first class type, so you don't need the enum keyword before its uses.

nophead commented 9 years ago

See http://forum.arduino.cc/index.php?topic=109584.0

joshpfosi commented 9 years ago

Worked great, thank you!