Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing manual (Class) based coroutines with .h and .cpp files #39

Closed
Code-Assembly opened this issue Sep 15, 2021 · 7 comments
Closed

Comments

@Code-Assembly
Copy link

Hi,

Right off the bat I would like to sincerely thank you for the awesome work you've done and this and your other libraries. Both the code quality and effort invested is truly commendable, and has certainly not gone unnoticed or unappreciated.

I'd like to ask if there is is any way in which the Sound Manager example could be implemented in a separate .h and .cpp file.
I would continuously get the following error undefined reference to `vtable for SoundManager'

As such I eventually settled for implementing everything in a single separate SoundManager.h file which compiles without errors.

@bxparks
Copy link
Owner

bxparks commented Sep 15, 2021

Thanks for the encouraging words!

With regards to the error message, I have not seen this. Can you send information on how to reproduce? What board? What tool chain?

@Code-Assembly
Copy link
Author

Hi silly of me not to include details:

Platform is STM32Duino on Platform IO the board is a RobotDyn APM32F103CB ( Effectively an STM32F103CB clone with 96MHz 128k Flash and 20k RAM )

I'm sure the issue is in my implementation so I'm rather hoping we can get an example that has a separate files but here is my non working implementation

SoundManager.h

#ifndef SoundManager_H
#define SoundManager_H

#include <Arduino.h>
#include <AceRoutine.h>

using namespace ace_routine;

enum Sound
{
    MUTE,
    NOTIFICATION,
    ALERT,
    WARNING,
    DANGER,
};

class SoundManager : public Coroutine
{
private:
    uint8_t _audioOutputPin;
    Sound _currentSound = MUTE;
    bool _loop;

public:
    void begin(uint8_t audioOutputPin);
    int virtual runCoroutine();
    void play(Sound sound, bool loop = false);
    void mute();
};

#endif

SoundManager.cpp

#include <Arduino.h>
#include "SoundManager.h"
#include "AudioNotes.h"

void SoundManager::begin(uint8_t audioOutputPin)
{
    _audioOutputPin = audioOutputPin;
}

int SoundManager::runCoroutine()
{
    COROUTINE_LOOP()
    {
        switch (_currentSound)
        {
        case Sound::NOTIFICATION:
            tone(_audioOutputPin, NOTE_B4);
            COROUTINE_DELAY(500);
            noTone(_audioOutputPin);
            COROUTINE_DELAY(125);

            tone(_audioOutputPin, NOTE_D4);
            COROUTINE_DELAY(125);
            noTone(_audioOutputPin);
            COROUTINE_DELAY(125 * 1.05);
            break;
        case Sound::ALERT:
            break;
        case Sound::WARNING:
            break;
        case Sound::DANGER:
            break;
        case Sound::MUTE:
            mute();
            break;
        }

        if (!_loop)
            mute();
    }
}

void SoundManager::play(Sound sound, bool loop)
{
    _currentSound = sound;
    _loop = loop;
}

void SoundManager::mute()
{
    _currentSound = Sound::MUTE;
    noTone(_audioOutputPin);
}

Main.cpp

#include <Arduino.h>
#include <AceCommon.h>
#include <AceRoutine.h>

#include "../lib/WLCConfig.h"
#include "../lib/SoundManager.h"

SoundManager soundManager;

void setup()
{
    pinMode(WLC::Pins::AUDIO_PWM_OUT, OUTPUT);
    soundManager.begin(WLC::Pins::AUDIO_PWM_OUT);
    soundManager.play(Sound::NOTIFICATION, true);
}

void loop()
{
    soundManager.runCoroutine();
}

@Code-Assembly
Copy link
Author

Working implementation everything in one file

SoundManager.h

#ifndef SoundManager_H
#define SoundManager_H

#include <Arduino.h>
#include <AceRoutine.h>
#include "AudioNotes.h"

using namespace ace_routine;

enum Sound
{
    MUTE,
    NOTIFICATION,
    ALERT,
    WARNING,
    DANGER,
};

class SoundManager : public Coroutine
{
private:
    uint8_t _audioOutputPin;
    Sound _currentSound = MUTE;
    bool _loop;

public:
    void begin(uint8_t audioOutputPin)
    {
        _audioOutputPin = audioOutputPin;
    }

    int runCoroutine() override
    {
        COROUTINE_LOOP()
        {
            switch (_currentSound)
            {
            case Sound::NOTIFICATION:
                tone(_audioOutputPin, NOTE_B4);
                COROUTINE_DELAY(500);
                noTone(_audioOutputPin);
                COROUTINE_DELAY(125);
                
                tone(_audioOutputPin, NOTE_D4);
                COROUTINE_DELAY(125);
                noTone(_audioOutputPin);
                COROUTINE_DELAY(125 * 1.05);

                // COROUTINE_DELAY(1000);
                break;
            case Sound::ALERT:
                break;
            case Sound::WARNING:
                break;
            case Sound::DANGER:
                break;
            case Sound::MUTE:
                mute();
                break;
            }

            if (!_loop)
                mute();
        }
    }

    void play(Sound sound, bool loop = false)
    {
        _currentSound = sound;
        _loop = loop;
    }

    void mute()
    {
        _currentSound = Sound::MUTE;
        noTone(_audioOutputPin);
    }
};

#endif

@bxparks
Copy link
Owner

bxparks commented Sep 18, 2021

I don't use PlatformIO, so I can't provide official support for it. But can you paste in the exact error message from the compiler? Maybe I can see something obvious.

Also, you have tried compiling your program with the Arduino IDE or CLI? I have used AceRoutine coroutines defined in separate *.h and *.cpp files without problems in many personal projects.

@Code-Assembly
Copy link
Author

The error i receive is

Building in release mode
Linking .pio/build/LaunchController/firmware.elf
/Users/aadil.cachalia/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: .pio/build/LaunchController/src/main.cpp.o: in function `_GLOBAL__sub_I_soundManager':
main.cpp:(.text.startup._GLOBAL__sub_I_soundManager+0x24): undefined reference to `vtable for SoundManager'
collect2: error: ld returned 1 exit status
*** [.pio/build/LaunchController/firmware.elf] Error 1

have used AceRoutine coroutines defined in separate *.h and *.cpp files without problems in many personal projects.

I'd really appreciate it I could see an example of how you do it. My limitation is likely in my lack of c++ knowledge, of file linking and language syntax ect. that is the root of the issue.

bxparks added a commit that referenced this issue Sep 22, 2021
…nstrate how to define them in separate files (see #39)
@bxparks
Copy link
Owner

bxparks commented Sep 22, 2021

I don't know the PlatformIO environment, but the main.cpp.o seems strange to me. Usually the object file is named main.o. Did you try compiling from a clean, i.e. wiping out *.o files and any compiler cache?

I looked at my projects where I defined coroutines in separate *.h and *.cpp files, but unfortunately almost all of them are in private repos. The one example that is in a public repo is waaay too complicated to use as an example.

So I just submitted 40a5d55 where I extracted the SoundManagerRoutine and SoundRoutine in the examples/SoundManager directory into separate files. Take a look in my develop branch. I verified that this works under both Arduino IDE, Arduino CLI and under Linux (using EpoxyDuino). It ought work under PlatformIO if you configure it properly.

@bxparks
Copy link
Owner

bxparks commented Sep 22, 2021

(Transferring this to Discussions because I don't think it's a bug in the library.)

Repository owner locked and limited conversation to collaborators Sep 22, 2021
@bxparks bxparks closed this as completed Sep 22, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants