3

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.

Arvo Bowen
  • 4,524
  • 6
  • 51
  • 109
  • What happens if you remove the trailing commas in your declaration? –  Sep 11 '19 at 02:03
  • Cannot reproduce on gdb. Could you [edit your question](https://stackoverflow.com/posts/57881046/edit) to and post a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)? –  Sep 11 '19 at 02:11
  • @Chipster I updated the question and added a link at the bottom so you can see exactly what I'm seeing. Also, I tried removing those trailing commas - still get the errors. That has been updated in the posted code link. – Arvo Bowen Sep 11 '19 at 03:07
  • constructor `LedAction(LedActionTypes action,...` – Juraj Sep 11 '19 at 09:25
  • @Juraj I had it that way at first and it was giving me errors are well. That's why I changed it that way. But I can update the source on the project (linked at the bottom of the question above). – Arvo Bowen Sep 11 '19 at 14:28
  • @Juraj So I changed that and tested it and as expected that produced more errors than I had in the question above. `2:18: error: variable or field 'Constructor' declared void - 2:18: error: 'LedActionTypes' was not declared in this scope - 2:41: error: expected primary-expression before 'int'` So that made things worse. – Arvo Bowen Sep 11 '19 at 14:33
  • only remove all `enum` in the code except of the declarations – Juraj Sep 11 '19 at 15:24
  • @Juraj as I said before, I have already tried that and started with it that way. I now have 16 errors as to where before I only had 8. So things got worse. Here is the updated code (https://www.tinkercad.com/things/4oQHS1Zf3tg). – Arvo Bowen Sep 11 '19 at 18:15

1 Answers1

1

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!).

Arvo Bowen
  • 4,524
  • 6
  • 51
  • 109
  • Side note: Talking to Tinkercad support I suggested that a great feature would be to add a property to each project or even each code block that keeps the version of the Arduino compiler the users wish to use. This way they can release new versions without the elaborate time it takes to test upgrades and just give the end-users the ability to choose what they want to compile with. I wouldn't think it would be that hard to implement and it would allow the old projects to stay on old compilers for compatibility as well as letting new projects get cutting edge compilers to use. – Arvo Bowen Sep 13 '19 at 13:34