2

First of all, I copied/paste th code to see if it compliles in Arduino IDE, and it does, so I guess it's not a C++ related issue but maybe something more Atmel Studio or linker related.

I recently decided to switch from Arduino IDE to Atmel Studio to develop and program Arduino boards.

I have this project where I use a .h/.c library that I wrote, which is located in "../Lib". I have added the library with "Add existing item" and "Add as Link", because I wanted to work with the original code not a copy (a few things still need to be added to it)

A first it builded without any problem, but then I added an extra function in the library called "determineWinningPosition()". Now compilation returns an error :

D:\Google Drive\ISIB\5 - Mecatronic\Controller_v5_AS\Controller_v5_AS\Controller_v5\Sketch.cpp(76,28): error: 'determineWinningPositions' was not declared in this scope
      determineWinningPositions();

The function prototype is declared in the library header "LetMeOut.h" :

#include <Arduino.h>
#include <Wire.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <EEPROM.h>
#include <stdlib.h>

// Key words
#define MOTOR1        (0)
#define MOTOR2        (1)
#define MAX_SPEED     (15)
#define SIZE_RAND_SEQ (100)
#define BUTTON_TIMEOUT (10) // -> 1s
#define WINNING_POS_TOLERANCE (3)
#define GLOBAL_STATE_SIZE (7)
#define STATE0        (3)
#define STATE1        (2)
#define STATE2        (0)
#define STATE3        (1)
#define START         (5)
#define STOP          (10)
#define CHANGE_SPEED  (15)
#define INIT_POS      (20)
#define START_SPEED   (25)
#define RESET_CMD     (30)
#define GO_TO_POS     (35)
#define UNLOCK_DOOR   (40)
#define LOCK_DOOR     (45)
#define CHANGE_WINNING_POS  (50)
#define TRUE          (1)
#define FALSE         (0)
#define EEPROM_1      (0)
#define EEPROM_2      (1)

// Pins
#define DIR_M1        (A0)
#define DIR_M2        (A1)
#define EN_M1         (A2)
#define EN_M2         (A3)
#define SCL_PIN       (A4)
#define SDA_PIN       (A5)
#define STARTED_PIN   (2)
#define A1_PIN        (3)
#define B1_PIN        (4)
#define A2_PIN        (5)
#define CTL_M1        (6)
#define B2_PIN        (7)
#define START_PIN     (8)
#define STOP_M2       (9)
#define SUCCEED_PIN   (10)
#define CTL_M2        (11)
#define STOP_M1       (12)
#define DOOR_PIN      (13) // LED

// Prototypes
void Timer1_ISR(void);
void receiveEvent(int howMany);
void requestEvent();
void initI2C(void);
void initMotors(void);
void initEncoder(void);
void initDirectionTimer(void);
void setMotorSpeed(uint8_t motor, uint8_t motorSpeed, uint8_t dir);
void setAllMotorSpeed(uint8_t motorSpeed);
void stopMotor(uint8_t motorID);
void stopAllMotors (void);
void startMotor(uint8_t motorID);
void startAllMotors (void);
void buttonManager(void);
void directionManager(void);
void i2cCommandManager(void);
void printPosition(bool b);
void goToPosition(uint8_t position1_, uint8_t position2_);
void readEncoder(void);
void determineWinningPositions(void);

The function is implemented in "LetMeOut.cpp" :

#include "LetMeOut.h"

extern uint8_t directionChangeCounter1, directionChangeCounter2;
extern uint8_t directionChangeCounterTopValue1;
extern uint8_t directionChangeCounterTopValue2;
extern bool direction1;
extern bool direction2;
extern bool counterChanged;
extern uint8_t button1Counter;
extern bool button1CounterStarted;
extern uint8_t button2Counter;
extern bool button2CounterStarted;
extern volatile uint8_t startButtonCounter;
extern volatile bool startButtonCounterStarted;

extern uint8_t cmd[3];
extern uint8_t globalState[GLOBAL_STATE_SIZE];
extern bool newCmd;
const uint8_t randomSeq[SIZE_RAND_SEQ] = {9, 15, 8, 10, 10, 10, 17, 12, 6, 16, 6, 8, 14, 15, 19, 15, 9, 20, 13, 17, 7, 15, 13, 15, 5, 7, 10, 6, 8, 9, 14, 9, 19, 11, 15, 17, 17, 7, 18, 12, 8, 20, 12, 11, 6, 16, 19, 17, 16, 10, 14, 14, 18, 13, 5, 20, 17, 10, 17, 12, 15, 12, 16, 12, 12, 18, 18, 19, 13, 16, 6, 7, 16, 17, 12, 11, 19, 12, 19, 13, 15, 18, 5, 7, 8, 8, 16, 16, 8, 14, 17, 17, 13, 6, 6, 8, 7, 10, 20, 13};
extern uint8_t index1;
extern uint8_t index2;

extern uint8_t speedSetting;
extern volatile bool started;
extern bool initDone;
extern bool doorUnlocked;

extern volatile bool currentA1, currentB1, currentA2, currentB2;
extern volatile int currentState1, previousState1, currentState2, previousState2, position1, position2;
extern volatile bool printPos;
extern uint8_t winningPosition1;
extern uint8_t winningPosition2;
extern volatile bool succeed;
extern volatile bool motor1Started;
extern volatile bool motor2Started;

extern int* winningPositionList1;
extern int* winningPositionList2;

/************************************************************************************************/
/********************************** Interrupts and Callbacks ************************************/
/************************************************************************************************/

// Interrupt service routine called at every timer 1 overflow : every 100 ms
// Used to measure time between every speed changes and to implement a timeout every 1s to prevent
// the user from "machine gunning" the buttons
void Timer1_ISR(void)
{
    // Increase both counters used for speed changes and notify the loop() there's been a change
    directionChangeCounter1++;
    directionChangeCounter2++;
    counterChanged = 1;

    // Prevent the user from "machine gunning" the buttons
    if (button1CounterStarted)
    {
        button1Counter++;
        if (button1Counter >= BUTTON_TIMEOUT)
        {
            button1CounterStarted = 0;
            button1Counter = 0;
        }
    }
    if (button2CounterStarted)
    {
        button2Counter++;
        if (button2Counter >= BUTTON_TIMEOUT)
        {
            button2CounterStarted = 0;
            button2Counter = 0;
        }
    }

    // Debounce START_PIN
    if (startButtonCounterStarted)
    {
        startButtonCounter++;
        if (startButtonCounter >= 2)
        {
            startButtonCounterStarted = 0;
            startButtonCounter = 0;
        }
    }
}

// Callback function that defines the behaviour in case of some received I2C bytes
void receiveEvent(int howMany)
{
    // Read the incoming bytes
    cmd[0] = Wire.read();
    if (Wire.available())
    cmd[1] = Wire.read();
    if (Wire.available())
    cmd[2] = Wire.read();
    // Get rid of any other unread message
    while (Wire.available() != 0)
    {
        Wire.read();
    }

    // Notify the loop() that there's a new command to be handled
    newCmd = 1;
}

// Callback function that defines the behaviour in case of a received request
// for a global state update -> send the global state to the Rapsberry Pi
void requestEvent()
{
    // Prepare the message to be sent
    globalState[0] = started;
    globalState[1] = succeed;
    globalState[2] = speedSetting;
    globalState[3] = doorUnlocked;
    globalState[4] = initDone;
    globalState[5] = winningPosition1;
    globalState[6] = winningPosition2;
    // Send the global state to the raspberry pi
    for (int i=0; i<GLOBAL_STATE_SIZE; i++)
    {
        Wire.write(globalState[i]);
    }
}

/************************************************************************************************/
/********************************** Initializations *********************************************/
/************************************************************************************************/

// Initialize the I2C
void initI2C(void)
{
    Wire.begin(0x18);
    Wire.onReceive(receiveEvent);
    Wire.onRequest(requestEvent);
    // Disable internal pullup
    digitalWrite(SCL_PIN, LOW);
    digitalWrite(SDA_PIN, LOW);
}

// Motor control related intializations
void initMotors(void)
{
    // Initialize timer 0 to generate a square wave on OC0A (CTL_M1 - D6)
    // Toggle OC0A on compare match (non-PWM mode), WF gen CTC mode
    TCCR0A = _BV(COM0A0) | _BV(WGM21);
    // Prescale = 1024  => period = 2 * 64us * (OCR0A+1);
    TCCR0B = _BV(CS02) | _BV(CS00);
    // Set initial value of compare (sets the frequency)
    OCR0A = MAX_SPEED;
    // => Changing OCR0A value will set frequency of the square wave and thus the motors speed

    // Initialize timer 2 to generate a square wave on OC2A (CTL_M2 - D11)
    // Toggle OC2B on compare match (non-PWM mode), WF gen CTC mode
    TCCR2A = _BV(COM2A0) | _BV(WGM21);
    // Prescale = 1024  => period = 2 * 64us * (OCR2A+1);
    TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
    // Set initial value of compare (sets the frequency)
    OCR2A = MAX_SPEED;
    // => Changing OCR0A value will set frequency of the square wave and thus the motors speed

    // Set the correct modes and initialize all the pins that are necessary for motor control
    pinMode(CTL_M1, OUTPUT);
    pinMode(CTL_M2, OUTPUT);
    pinMode(DIR_M1, OUTPUT);
    pinMode(DIR_M2, OUTPUT);
    pinMode(EN_M1, OUTPUT);
    digitalWrite(EN_M1, LOW);
    pinMode(EN_M2, OUTPUT);
    digitalWrite(EN_M2, LOW);
}

// Initialize pins and interrupts for the encoder
void initEncoder(void)
{
    // Configure pin change interrupts (PCINT) on A1, B1, A2 and B2
    // -> PCIE2 group
    PCICR = _BV(PCIE2);
    // Configure PCIE2 interrupt mask
    PCMSK2 = _BV(PCINT19) | _BV(PCINT20) | _BV(PCINT21) | _BV(PCINT23);
    pinMode(A1_PIN, INPUT);
    pinMode(B1_PIN, INPUT);
    pinMode(A2_PIN, INPUT);
    pinMode(B2_PIN, INPUT);
}

// Initialize timer1 to overflow every 100 ms (used for timing related things)
void initDirectionTimer(void)
{
    // Timer 1 config : normal mode
    TCCR1A = 0;
    // Prescaler 64 ; CTC mode
    TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12);
    TIMSK1 = 0b00000010;
    // Initiate Timer 1 and compare A value
    TCNT1 = 0;
    OCR1A = 25000;  // overflow every 100ms
}

/************************************************************************************************/
/****************************** Motor-related functions *****************************************/
/************************************************************************************************/

// Set the speed of a particular motor
void setMotorSpeed(uint8_t motor, uint8_t motorSpeed, uint8_t dir)
{
    // Make sure the speed isn't too fast
    if (motorSpeed < MAX_SPEED)
    motorSpeed = MAX_SPEED;
    // Set the speed by setting OCRxA and the direction by setting DIR_Mx pin
    if (motor == MOTOR1)
    {
        OCR0A = motorSpeed;
        digitalWrite(DIR_M1, dir);
    }
    else if (motor == MOTOR2)
    {
        OCR2A = motorSpeed;
        digitalWrite(DIR_M2, dir);
    }
}

// Set the speed of both motors at the same time
void setAllMotorSpeed(uint8_t motorSpeed)
{
    // Make sure the speed isn't too fast
    if (motorSpeed < MAX_SPEED)
    motorSpeed = MAX_SPEED;

    OCR0A = motorSpeed;
    OCR2A = motorSpeed;
}

// Stop a particular motor by setting its "Not_EN" pin
void stopMotor(uint8_t motorID)
{
    if (motorID == MOTOR1)
    {
        digitalWrite(EN_M1, HIGH);
    }
    else
    {
        digitalWrite(EN_M2, HIGH);
    }
}

// Stop all motors by setting their "Not_EN" pin
void stopAllMotors (void)
{
    digitalWrite(EN_M1, HIGH);
    digitalWrite(EN_M2, HIGH);
}

// Start a particular motor by clearing its "Not_EN" pin
void startMotor(uint8_t motorID)
{
    if (motorID == MOTOR1)
    {
        digitalWrite(EN_M1, LOW);
    }
    else
    {
        digitalWrite(EN_M2, LOW);
    }
}

// Start all motors by clearing their "Not_EN" pin
void startAllMotors (void)
{
    digitalWrite(EN_M1, LOW);
    digitalWrite(EN_M2, LOW);
}

/************************************************************************************************/
/********************************** Other functions *********************************************/
/************************************************************************************************/

// Check is the player has pushed the button to stop the needles
// and implement corresponding behavior
void buttonManager(void)
{
    // Has player pushed button 1 ?
    if (!digitalRead(STOP_M1))
    {
        // If we're not in a button timeout period, stop the motors
        if (!button1CounterStarted)
        {
            stopMotor(MOTOR1);
            motor1Started = 0;
            button1CounterStarted = 1;
        }
    }
    else
    {
        if (!button1CounterStarted)
        {
            startMotor(MOTOR1);
            motor1Started = 1;
        }
        // Keep the motor stopped during the timeout period
        else
        {
            stopMotor(MOTOR1);
            motor1Started = 0;
        }
    }

    // Has player pushed button 2 ?
    if (!digitalRead(STOP_M2))
    {
        // If we're not in a button timeout period, stop the motors
        if (!button2CounterStarted)
        {
            stopMotor(MOTOR2);
            motor2Started = 0;
            button2CounterStarted = 1;
        }
    }
    else
    {
        if (!button2CounterStarted)
        {
            startMotor(MOTOR2);
            motor2Started = 1;
        }
        // Keep the motor stopped during the timeout period
        else
        {
            stopMotor(MOTOR2);
            motor2Started = 0;
        }
    }

    if (!digitalRead(STOP_M1) && !digitalRead(STOP_M2))
    {
        bool won1 = 0, won2 = 0;

        // Check if needle 1 is in a winning position
        for (int i=0; i<2*WINNING_POS_TOLERANCE+1; i++)
        {
            if (position1 == winningPositionList1[i])
            {
                won1 = 1;
                break;
            }
        }

        // Check if needle 2 is in a winning position
        for (int i=0; i < 2*WINNING_POS_TOLERANCE+1; i++)
        {
            if (position2 == winningPositionList2[i])
            {
                won2 = 1;
                break;
            }
        }       

        // If both are winnin, the player won
        if (won1 && won2)
        {
            digitalWrite(DOOR_PIN, HIGH);
            doorUnlocked = TRUE;
            Serial.println("WINNER");
            succeed = 1;
            started = 0;
            digitalWrite(STARTED_PIN, started);
            digitalWrite(SUCCEED_PIN, succeed);
            // Make sure all motors are stopped (in case the switches has been pushed between the previous "if" and this one
            // (happened once...)
            stopAllMotors();
        }
    }
}

// Manages the direction changes
// This function is called whenever on of the direction change counter value has changed
void directionManager(void)
{
    uint8_t newSpeed;
    // Check if our counter has overflowed
    if (directionChangeCounter1 >= directionChangeCounterTopValue1)
    {
        // Switch the direction
        direction1 = !direction1;

        // Reset the counter
        directionChangeCounter1 = 0;

        // Find the next value in the randomSeq array -> time intervals are random
        index1 = (index1+1)%SIZE_RAND_SEQ;
        directionChangeCounterTopValue1 = randomSeq[index1];

        // Modify the speed according to the time value
        // long time value <=> faster speed
        // short time value <=> slower speed
        if (directionChangeCounterTopValue1 < 10)
        newSpeed = speedSetting + 4;
        else if (directionChangeCounterTopValue1 < 15)
        newSpeed = speedSetting + 2;
        else
        newSpeed = speedSetting;
        setMotorSpeed(MOTOR1, newSpeed, direction1);
    }
    // Same as for motor 1...
    if (directionChangeCounter2 >= directionChangeCounterTopValue2)
    {
        direction2 = !direction2;
        directionChangeCounter2 = 0;
        index2 = (index2+1)%SIZE_RAND_SEQ;
        directionChangeCounterTopValue2 = randomSeq[index2];
        if (directionChangeCounterTopValue2 < 10)
        newSpeed = speedSetting + 4;
        else if (directionChangeCounterTopValue2 < 15)
        newSpeed = speedSetting + 2;
        else
        newSpeed = speedSetting;
        setMotorSpeed(MOTOR2, newSpeed, direction2);
    }
}

// Defines how the uC reacts to i2c commands from raspberry pi server
void i2cCommandManager(void)
{
    // Did we get any command from the server ?
    if (newCmd)
    {
        //    Serial.print("i2c = ");
        //    Serial.print(cmd[0]);
        //    Serial.print(" ");
        //    Serial.print(cmd[1]);
        //    Serial.print(" ");
        //    Serial.println(cmd[2]);
        switch (cmd[0])
        {
            case CHANGE_SPEED :     // Change the speed
            speedSetting = cmd[1];
            setAllMotorSpeed(speedSetting);
            Serial.print("speed = ");
            Serial.println(speedSetting);
            break;
            case START :          // Start and reset the game (unused, replaced by START_SPEED)
            startAllMotors();
            started = 1;
            succeed = 0;
            digitalWrite(STARTED_PIN, started);
            digitalWrite(SUCCEED_PIN, succeed);
            motor1Started = 1;
            motor2Started = 1;
            digitalWrite(DOOR_PIN, LOW);
            doorUnlocked = FALSE;
            Serial.println("START");
            break;
            case STOP :         // Stop the game
            stopAllMotors();
            started = 0;
            digitalWrite(STARTED_PIN, started);
            motor1Started = 0;
            motor2Started = 0;
            Serial.println("STOP");
            break;
            case INIT_POS :     // Calibrate the encoder according to the needles positions the user typed on the html form
            position1 = cmd[1];
            position2 = cmd[2];
            initDone = TRUE;
            Serial.print("Init Pos = ");
            Serial.print(position1);
            Serial.print(" ");
            Serial.println(position2);
            break;
            case START_SPEED :  // Reset, start and set the speed
            startAllMotors();
            started = 1;
            succeed = 0;
            digitalWrite(STARTED_PIN, started);
            digitalWrite(SUCCEED_PIN, succeed);
            motor1Started = 1;
            motor2Started = 1;
            digitalWrite(DOOR_PIN, LOW);
            doorUnlocked = FALSE;
            Serial.print("START SPEED = ");
            speedSetting = cmd[1];
            setAllMotorSpeed(speedSetting);
            Serial.print("speed = ");
            Serial.println(speedSetting);
            break;
            case RESET_CMD :    // Reset the game without starting it
            stopAllMotors();
            succeed = 0;
            started = 0;
            digitalWrite(STARTED_PIN, started);
            digitalWrite(SUCCEED_PIN, succeed);
            motor1Started = 0;
            motor2Started = 0;
            digitalWrite(DOOR_PIN, LOW);
            doorUnlocked = FALSE;
            Serial.println("RESET");
            break;
            case GO_TO_POS :    // Make the needles go to a certain position
            Serial.print("Go to pos ");
            Serial.print(cmd[1]);
            Serial.print(" ");
            Serial.println(cmd[2]);
            goToPosition(cmd[1], cmd[2]);
            break;
            case UNLOCK_DOOR :  // Unlock the door
            digitalWrite(DOOR_PIN, HIGH);
            doorUnlocked = TRUE;
            Serial.println("Unlock the door");
            break;
            case LOCK_DOOR :    // Lock the door
            digitalWrite(DOOR_PIN, LOW);
            doorUnlocked = FALSE;
            Serial.println("Lock the door");
            break;
            case CHANGE_WINNING_POS :   // Redefine the winning position, which is written on the EEPROM to keep it when the uC has been stopped
            winningPosition1 = cmd[1];
            winningPosition2 = cmd[2];
            EEPROM.write(EEPROM_1, winningPosition1);
            EEPROM.write(EEPROM_2, winningPosition2);
            determineWinningPositions();
            Serial.print("Change win. pos. to (");
            Serial.print(cmd[1]);
            Serial.print(",");
            Serial.print(cmd[2]);
            Serial.println(")");
            break;
        }
        newCmd = 0;
    }
}

// Print the current needles position for debug purposes
void printPosition(bool b)
{
    if (printPos && b)
    {
        Serial.print(position1);
        Serial.print(" ");
        Serial.println(position2);
        printPos = 0;
    }
}

// Make the needles go to the position the user submitted on the html form
void goToPosition(uint8_t position1_, uint8_t position2_)
{
    // Set the speed pretty slow and make sure the motors are started
    setAllMotorSpeed(45);
    startAllMotors();

    bool okPos1 = 0, okPos2 = 0;

    // turn the needles clockwise until the both reach the desired position
    while(!(okPos1 && okPos2))
    {
        if (position1 == position1_)
        {
            stopMotor(MOTOR1);
            okPos1 = 1;
        }
        if (position2 == position2_)
        {
            stopMotor(MOTOR2);
            okPos2 = 1;
        }
    }
    setAllMotorSpeed(speedSetting);
}

// Determine the new motor position when there's been a change on the encoder pins
void readEncoder(void)
{
    // The binary combinations of A1 and B1 is always, in decimal :
    // 3 2 0 1 3 2 0 1 3 2 0 1  ... when the motor is rotating clockwise
    // 1 0 2 3 1 0 2 3 1 0 2 3  ... when the motor is rotating anticlockwise
    // Knowing this we can deduce from A1-B1 combinations which way the motor is turning
    currentA1 = digitalRead(A1_PIN);
    currentB1 = digitalRead(B1_PIN);
    //  Serial.print(currentA1);
    //  Serial.print(currentB1);
    //  Serial.print(" ");
    currentState1 = ((char)currentA1<<1) + currentB1;
    if (currentState1 != previousState1)
    {
        if (currentState1 == STATE0)
        {
            if (previousState1 == STATE3)
            {
                position1++;
                if (position1 == 60)
                position1 = 0;
            }
            else if (previousState1 == STATE1)
            {
                position1--;
                if (position1 == -1)
                position1 = 59;
            }
        }

        if (currentState1 == STATE1)
        {
            if (previousState1 == STATE0)
            {
                position1++;
                if (position1 == 60)
                position1 = 0;
            }
            else if (previousState1 == STATE2)
            {
                position1--;
                if (position1 == -1)
                position1 = 59;
            }
        }

        if (currentState1 == STATE2)
        {
            if (previousState1 == STATE1)
            {
                position1++;
                if (position1 == 60)
                position1 = 0;
            }
            else if (previousState1 == STATE3)
            {
                position1--;
                if (position1 == -1)
                position1 = 59;
            }
        }

        if (currentState1 == STATE3)
        {
            if (previousState1 == STATE2)
            {
                position1++;
                if (position1 == 60)
                position1 = 0;
            }
            else if (previousState1 == STATE0)
            {
                position1--;
                if (position1 == -1)
                position1 = 59;
            }
        }
        previousState1 = currentState1;
        printPos = 1;
    }

    currentA2 = digitalRead(A2_PIN);
    currentB2 = digitalRead(B2_PIN);
    //  Serial.print(currentA2);
    //  Serial.println(currentB2);
    currentState2 = ((char)currentA2<<1) + currentB2;
    if (currentState2 != previousState2)
    {
        if (currentState2 == STATE0)
        {
            if (previousState2 == STATE3)
            {
                position2++;
                if (position2 == 60)
                position2 = 0;
            }
            else if (previousState2 == STATE1)
            {
                position2--;
                if (position2 == -1)
                position2 = 59;
            }
        }

        if (currentState2 == STATE1)
        {
            if (previousState2 == STATE0)
            {
                position2++;
                if (position2 == 60)
                position2 = 0;
            }
            else if (previousState2 == STATE2)
            {
                position2--;
                if (position2 == -1)
                position2 = 59;
            }
        }

        if (currentState2 == STATE2)
        {
            if (previousState2 == STATE1)
            {
                position2++;
                if (position2 == 60)
                position2 = 0;
            }
            else if (previousState2 == STATE3)
            {
                position2--;
                if (position2 == -1)
                position2 = 59;
            }
        }

        if (currentState2 == STATE3)
        {
            if (previousState2 == STATE2)
            {
                position2++;
                if (position2 == 60)
                position2 = 0;
            }
            else if (previousState2 == STATE0)
            {
                position2--;
                if (position2 == -1)
                position2 = 59;
            }
        }
        previousState2 = currentState2;
        printPos = 1;
    }
}

void determineWinningPositions(void)
{
    int firstPos = winningPosition1-WINNING_POS_TOLERANCE;

    if (firstPos < 0)
        firstPos =+ 60;

    for (int i=0; i<(2*WINNING_POS_TOLERANCE+1); i++)
    {
        winningPositionList1[i] = (firstPos+i)%60;
    }

    firstPos = winningPosition2-WINNING_POS_TOLERANCE;

    if (firstPos < 0)
    firstPos =+ 60;

    for (int i=0; i<(2*WINNING_POS_TOLERANCE+1); i++)
    {
        winningPositionList2[i] = (firstPos+i)%60;
    }
}

The header is included at the beginning of "Sketch.cpp" :

#include <Arduino.h>
#include "LetMeOut.h"

ISR(TIMER1_COMPA_vect );
ISR(PCINT2_vect );

bool debug = 0;
uint8_t directionChangeCounter1 = 0, directionChangeCounter2 = 0;
uint8_t directionChangeCounterTopValue1 = 10;
uint8_t directionChangeCounterTopValue2 = 10;
bool direction1 = 0;
bool direction2 = 0;
bool counterChanged = 0;
uint8_t button1Counter = 0;
bool button1CounterStarted = FALSE;
uint8_t button2Counter = 0;
bool button2CounterStarted = FALSE;
volatile uint8_t startButtonCounter = 0;
volatile bool startButtonCounterStarted = FALSE;

uint8_t cmd[3] = {0,0,0};
uint8_t globalState[GLOBAL_STATE_SIZE];
bool newCmd = 0;

uint8_t index1 = 0;
uint8_t index2 = 64;

uint8_t speedSetting = MAX_SPEED;
volatile bool started = 0;
bool initDone = FALSE;
bool doorUnlocked = FALSE;

volatile bool currentA1, currentB1, currentA2, currentB2;
volatile int currentState1, previousState1, currentState2, previousState2, position1, position2;
volatile bool printPos = 0;
uint8_t winningPosition1;
uint8_t winningPosition2;
volatile bool succeed = 0;  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
volatile bool motor1Started = 0;
volatile bool motor2Started = 0;

int* winningPositionList1;
int* winningPositionList2;

void setup()
{
    Serial.begin(2000000);
    Serial.println("****************************************************************");
    Serial.println("******************** L'horloge déjantée ************************");
    Serial.println("************* Eric Bohnes - ISIB 2017-2018**********************");
    Serial.println("****************** Master 2 Electronique ***********************");
    Serial.println("****************** Cours de Mécatronique ***********************");
    Serial.println("*****Collaboration avec l'Escape Game LET ME OUT Bruxelles *****");
    Serial.println("****************************************************************\n\n");
    initMotors();
    initDirectionTimer();
    initI2C();
    initEncoder();

    // Set the player's STOP buttons on INPUT_PULLUP
    pinMode(STOP_M1, INPUT_PULLUP);
    pinMode(STOP_M2, INPUT_PULLUP);
    pinMode(SUCCEED_PIN, OUTPUT);
    pinMode(STARTED_PIN, OUTPUT);
    // Enable global interrupts
    interrupts();
    pinMode(START_PIN, INPUT_PULLUP);
    stopAllMotors();
    winningPosition1 = EEPROM.read(EEPROM_1);
    winningPosition2 = EEPROM.read(EEPROM_2);
    digitalWrite(STARTED_PIN, started);
    digitalWrite(SUCCEED_PIN, succeed);

    winningPositionList1 = (int*)malloc((2*WINNING_POS_TOLERANCE+1)*sizeof(int));   
    winningPositionList2 = (int*)malloc((2*WINNING_POS_TOLERANCE+1)*sizeof(int));
    determineWinningPositions();
}

void loop()
{
    // If the player didn't succeed yet, check we must change a direction or if the player pushed a button
    if (!succeed)
    {
        // Check if it's time to change direction
        if (counterChanged)
        directionManager();
        // If the game is started, poll the buttons
        if (started)
        buttonManager();
        // Set the parameter TRUE for debugging purposes
        printPosition(FALSE);
    }
    i2cCommandManager();

    if (!digitalRead(START_PIN))
    {
        if (!startButtonCounterStarted)
        {
            startAllMotors();
            started = 1;
            succeed = 0;
            digitalWrite(STARTED_PIN, started);
            digitalWrite(SUCCEED_PIN, succeed);
            motor1Started = 1;
            motor2Started = 1;
            doorUnlocked = FALSE;
            digitalWrite(DOOR_PIN, LOW);
            Serial.println("Started by pin");
            startButtonCounterStarted = TRUE;
            startButtonCounter = 0;
        }
    }
}

ISR(TIMER1_COMPA_vect)
{
    Timer1_ISR();
}

ISR(PCINT2_vect)
{
    readEncoder();
}

As I said before, I copied/pasted the sketch in Arduino IDE and it compiles without any errors with this tool. When trying to compile with Atmel Studio, I tried to build/rebuild the solution, the sketch itself, with and without cleaning first, still get the error.

Here is a solution explorer printscreen :

Solution explorer printscreen

Any clue would be appreciated !

Best regards.

Eric

ricothebrol
  • 81
  • 12
  • The code snippets you show, and the error output, they are copied and pasted? You have not tried to rewrite any part of them inside the question itself? You're sure the spelling and casing of the symbol is the exact same in all locations? Does it work with other symbols or functions declared in the header file? – Some programmer dude Jan 29 '18 at 07:07
  • I first shortened my code snippets but now I edited the question and pasted the whole thing. – ricothebrol Jan 29 '18 at 07:20
  • We don't need to see everything. A [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) would be preferred, but a statement saying that the code shown is actual as-is and copy-pasted code from the actual source will be just as fine. – Some programmer dude Jan 29 '18 at 07:22
  • You have posted a wall of code, none of it is relevant. Produce a [mcve]. Anyway, if it looks like the compiler doesn't see your code, 98 times out of 100 it doesnt't see your code, most probably because the file it is compiling and the file you are modifying are two different files. – n. m. could be an AI Jan 29 '18 at 07:25
  • Sorry I thought you asked me for the whole code... – ricothebrol Jan 29 '18 at 07:33
  • I first thought it was that kind of "different sources" issue but the I tried to comment out a #define in "LetMeOut.h" and the compiler sees it is missing as it then returns an error... – ricothebrol Jan 29 '18 at 07:34
  • Just did another test : I recreated the project in Atmel Studio, and now it compiles just fine ! I think in a way Atmel Studio doesn't update the whole thing when I update my library. How can I force it to properly recompile everything ? – ricothebrol Jan 29 '18 at 08:17
  • I now tried to add a dummy function dummyFunction() to the library with the new project, and I get the same result : " 'dummyFunction' was not declared in this scope". Is it that weird to modify a library ? – ricothebrol Jan 29 '18 at 09:14

0 Answers0