Search code examples
c++arduinotinkercad

Unhelpful errors in Tinkercad writing Arduino c++ code


Sorry if some of my source looks really bad. This is my first attempt writing Arduino code as well as c++. I usually stay in my comfort zone of c#.

I'm getting the following errors when trying to run my source on a Tinkercad circuit. The way Tinkercad spits out errors is horrible for learning. Anyone who might be able to point out my mistakes that it is having a fit with would be very helpful.

Errors

 - 2:23: error: use of enum 'LedActionTypes' without previous
   declaration
 - 4:23: error: use of enum 'SignalTypes' without previous declaration
 - 4:64: error: use of enum 'SignalDirections' without previous declaration
 - 5:23: error: use of enum 'SignalTypes' without previous declaration
 - 5:64: error: use of enum 'SignalDirections' without previous declaration
 - 5:103: error: use of enum 'DigitalSignalValues' without previous declaration
 - 8:16: error: variable or field 'AddAction' declared void
 - 8:16: error: 'LedAction' was not declared in this scope

My source code

/* Enums */
enum SignalTypes
{
    General = 0,
    Analog = 1,
    Digital = 2,
};

enum SignalDirections
{
    Inbound = 0x0,
    Outbound = 0x1,
};

enum DigitalSignalValues
{
    Low = 0x0,
    High = 0x1,
};

enum LedActionTypes
{
    None = 0,
    ChangeBrightness = 1,
};

/* LED Action object */
class LedAction {
    // Functions
    void Constructor(enum LedActionTypes action, int intensity, int delay)
    {
        // Check for valid intensity value
        if (intensity < 0)
            intensity = 0;
        if (intensity > 255)
            intensity = 255;
        Intensity = intensity;

        Finished = false;
        Action = action;

        CompleteOn = millis() + delay;
    }

public:
    // Properties
    boolean Finished;
    enum LedActionTypes Action = None;
    int Intensity = 0;
    unsigned long CompleteOn = 0;


    // Constructor
    LedAction()
    {
        Constructor(Action, Intensity, 0);
    }
    LedAction(enum LedActionTypes action)
    {
        Constructor(action, Intensity, 0);
    }
    LedAction(enum LedActionTypes action, int intensity, int delay)
    {
        Constructor(action, intensity, delay);
    }


    // Methods
    void Loop() {
        if (Finished) { return; }

        unsigned long currentTimeStamp = millis();

        if (CompleteOn >= currentTimeStamp)
        {
            //Process the action
            Finished = true;
        }
    }
};


/* LED object */
class Led {
    // Functions
    void Constructor(enum SignalTypes signalType, byte pbPin, enum SignalDirections signalDirection, int intensity)
    {
        // Check for valid intensity value
        if (intensity < 0)
            intensity = 0;
        if (intensity > 255)
            intensity = 255;
        Intensity = intensity;

        Constructor(SignalType, PBPin, SignalDirection, DigitalSignalValue);
    }
    void Constructor(enum SignalTypes signalType, byte pbPin, enum SignalDirections signalDirection, enum DigitalSignalValues signalValue)
    {
        SignalType = signalType;
        PBPin = pbPin;
        SignalDirection = signalDirection;
        DigitalSignalValue = signalValue;
    }

public:
    // Properties
    byte PBPin;
    int Intensity;
    enum DigitalSignalValues DigitalSignalValue;
    enum SignalTypes SignalType = Analog;
    enum SignalDirections SignalDirection = Outbound;
    LedAction Actions[20]{ LedAction(None) };


    // Constructor
    Led()
    {
        Constructor(SignalType, 0, SignalDirection, 0);
    }
    Led(byte pbPin, enum SignalDirections signalDirection, int intensity)
    {
        Constructor(SignalType, pbPin, signalDirection, intensity);
    }
    Led(byte pbPin, enum SignalDirections signalDirection, enum DigitalSignalValues signalValue)
    {
        Constructor(SignalType, pbPin, signalDirection, signalValue);
    }
    Led(enum SignalTypes signalType, byte pbPin, enum SignalDirections signalDirection, int intensity)
    {
        Constructor(signalType, pbPin, signalDirection, intensity);
    }
    Led(enum SignalTypes signalType, byte pbPin, enum SignalDirections signalDirection, enum DigitalSignalValues signalValue)
    {
        Constructor(signalType, pbPin, signalDirection, signalValue);
    }


    // Methods
    void Setup()
    {
        switch (SignalType)
        {
        case Analog:
            analogWrite(PBPin, Intensity);
            break;
        case Digital:
            digitalWrite(PBPin, Intensity);
            pinMode(PBPin, SignalDirection);
            break;
        }
    }

    void Loop()
    {
        int n;

        // Loop through all actions and find unfinished ones then fire them off
        for ( n=0 ; n<20 ; ++n )
        {
            if (!Actions[n].Finished)
            {
                Actions[n].Loop();
                if (Actions[n].Finished)
                {
                    //Action was just flagged ready to process
                    switch (Actions[n].Action)
                    {
                    case ChangeBrightness:
                        digitalWrite(PBPin, Actions[n].Intensity);
                        break;
                    }

                }
            }
        }
    }

    void AddAction(LedAction action)
    {
        int n;

        // Loop through all actions and find an unfinished one then reuse it
        for (n = 0; n < 20; ++n)
        {
            if (!Actions[n].Finished)
            {
                action.Finished = false;
                Actions[n] = action;
                break;
            }
        }
    }

    void ClearAllActions()
    {
        int n;

        // Loop through all actions and mark all as finished
        for (n = 0; n < 20; ++n)
        {
            if (!Actions[n].Finished)
            {
                Actions[n].Finished = true;
            }
        }
    }
};

An example of the code on Tinkercad Circuits can be found at... https://www.tinkercad.com/things/gmGeFVKOA3e-adrunio-test/editel

Once on the page, click the "Simulate" play button (bottom left) and then hit the "Start Simulation" button at the top. You should see the same errors I'm seeing.


Solution

  • OK, so I think I found my answer...

    After having a few conversations with Tinkercad and the great support team there I was told that they use an old version of Arduino to compile their code. Well, all the code I'm writing and the IDE I'm writing in are based on the latest releases of everything. I think this is where my issue starts to happen.

    Currently, when trying to compile the following code in the current version that Tinkercad uses I get the respective error that follows...

    enum TestEnum
    {
        OptOne = 1,
        OptTwo = 2
    };
    
    class TestClass {
    private:
        void InitilizeClass(enum TestEnum te)
        { }
    
    public:
        TestClass(enum TestEnum te)
        { }
    };
    
    void setup()
    { }
    
    void loop()
    { }
    

    As you can see, I'm trying to create a function in my class called InitializeClass() that takes my enum as a parameter. The compiler does not like that one bit, and the error highlighting along with the error returned are horrible for some reason telling me nothing! enter image description here

    However, if I change the class to only use the enum in the constructor itself, that seems to compile just fine with no errors.

    enum TestEnum
    {
        OptOne = 1,
        OptTwo = 2
    };
    
    class TestClass {
    private:
        void InitilizeClass()
        { }
    
    public:
        TestClass(enum TestEnum te)
        { }
    };
    
    void setup()
    { }
    
    void loop()
    { }
    

    The Problem

    I wanted to create a class that has as least repetitive code as possible, this is usually the way I try and code in general. If I have to type the same code twice... Start looking at making it a function. This way a) there is less code and b) if you ever need to change the logic you're changing it in one place rather than multiple places. So I start out usually making my classes look like this...

    enum TestEnum
    {
        OptOne = 1,
        OptTwo = 2
    };
    
    class TestClass {
    private:
        void InitilizeClass(enum TestEnum te, int n, int t)
        {
            if (n < 0)
                n = 0;
            if (n > 255)
                n = 255;
            TE = te;
            N = n;
            T = t;
        }
    
    public:
        enum TestEnum TE = OptOne;
        int N = 0;
        int T = 0;
    
        TestClass(enum TestEnum te)
        { InitilizeClass(te, 0, 0); }
        TestClass(enum TestEnum te, int n)
        { InitilizeClass(te, n, 0); }
        TestClass(enum TestEnum te, int n, int t)
        { InitilizeClass(te, n, t); }
    };
    
    void setup()
    { }
    
    void loop()
    { }
    

    This works perfectly fine in VS IDE (c++) as well as the latest Arduino IDE. However, since Tinkercad is using an old Arduino compiler it has a fit with me using the enums in a private class function. (Update: Just found out this happens in ANY class function! Not just a private one.)

    The Solution

    So this whole time, I have been thinking with a c# mentality when coding my Arduino project when I should have been thinking more c++ like. Well, in my defense I am after all a c# guy through and through. I love it SO much more the c++. Well in almost every way. There are apparently exceptions. I recently found out, that while c# does not allow it c++ DOES allow you to overload class constructors! That changes everything for the way I would write my classes in c++. Now there is no reason for the private class function to initialize the class. So I can just have something like the following...

    enum TestEnum
    {
        OptOne = 1,
        OptTwo = 2
    };
    
    class TestClass {
    public:
        enum TestEnum TE = OptOne;
        int N = 0;
        int T = 0;
    
        TestClass(enum TestEnum te)
        { TestClass(te, 0, 0); }
        TestClass(enum TestEnum te, int n)
        { TestClass(te, n, 0); }
        TestClass(enum TestEnum te, int n, int t)
        { TestClass(te, n, t); }
    };
    
    void setup()
    { }
    
    void loop()
    { }
    

    That my friends compiles completely fine in the old Arduino compilers. It also saves me some space for other code (these ATTiny chips are not huge so a smaller program is always a win!).