Как сделать массив указателей на функции из типов определенных функций - PullRequest
0 голосов
/ 05 июня 2019

Я пытаюсь реализовать класс NeopixelAnimator этой библиотеки: https://github.com/Makuna/NeoPixelBus.

Я создал класс аниматора, который содержит экземпляр библиотечного класса NeoPixelAnimator. Для запуска анимации мне нужно позвонить: .StartAnimation(uint16_t indexAnimation, uint16_t duration, UpdateCallback animUpdate).

Моя цель - создать очередь анимаций, которые анимируются друг за другом. Вторая анимация должна начаться, когда первая будет завершена. Поскольку сама библиотека не предоставляет способ сделать это, я создал вектор, представляющий очередь, он содержит анимацию для анимации и ее цвет.

Проблема в том, что функция .StartAnimation() ожидает параметр UpdateCallback, который является функцией обратного вызова, которая запускается при вызове функции .UpdateAnimations().

Анимации будут запускаться переключателями, подключенными к Arduino Due, которые вызывают функцию .add() (не в коде примера). Сейчас я хочу проверить, работает ли он, добавив одну анимацию в .init().

Мой план состоял в том, чтобы создать массив указателей на функции, которые указывают на эти функции обратного вызова. Проблема в том, что я не могу заставить типы данных совпадать.

Помощь будет принята с благодарностью. Кроме того, отзывы о том, как подходить к решению подобных проблем и создавать код, будут с благодарностью.

Я использую platformIO с библиотекой Arduino на плате Arduino Due.

defines.h:

//Amount of different animations should correspond to the number of callback functions
#define NUMBER_OF_ANIMATIONS 2

//Animation ID's:
#define WIPE_ANIM 0

//Colour ID's:
#define GREEN 0

animator.h:

#include <arduino.h>
#include <NeoPixelAnimator.h>
#include <NeoPixelBrightnessBus.h>
#include <array>
#include <vector>

class Animator
{
public:
private:

//NeoPixel animation time management object
    NeoPixelAnimator animations;

//Neopixel strip communication object
    NeoPixelBrightnessBus<NeoGrbFeature, Neo800KbpsMethod> strip1; //NeoPixel strip 1 object

//Array of AnimUpdateCallback function pointers to the animation callback functions
     AnimUpdateCallback (*_callbackPt[NUMBER_OF_ANIMATIONS])(const AnimationParam &param);

//Vector of arrays to store animations to be animated (animId, colorId)
    std::vector<std::array<uint8_t, 2>> _animationQueue;

public:
    Animator();
    void init();
    void run();
    void add(uint8_t animId, uint8_t colorId);

private:
    void updateQueue();

animator.cpp:

#include <Animator.h>

//Default constructor
Animator::Animator() : strip1(NUMBER_OF_LEDS_1, LED_PIN_1),
                       _callbackPt{wipeColorAnim, wipeColorAnim}
{
}

//Inititalisation function, inits strips, sets brightness for strips, sets inital color with wipeColorAnim()
void Animator::init()
{
    strip1.Begin();

    strip1.SetBrightness(100);

    add(WIPE_ANIM, GREEN);        //wipeColor strip1 with Green
}

//Add aniamtion to the queue
void Animator::add(uint8_t animId, uint8_t colorId)
{
    //Create array storing the animation ID and its color
    std::array<uint8_t, 2> animation{animId, colorId};

    //Add the animation to the end of the queue
    _animationQueue.push_back(animation);
}

//Loop this function to update animations
void Animator::run()
{
    //if there is an animation running
    if (animations.IsAnimating())
    {

        animations.UpdateAnimations(); //update running animation
        strip1.Show();
    }
    else
    {
        updateQueue();
    }
}

//Checks whether there is an animation in the queue if so it's started
void Animator::updateQueue()
{
    //if there is an animation waiting in the queue
    if (!_animationQueue.empty())
    {
        //Start next animation in queue on channel 0 with specified time and animUpdate callback function (channel, time, callback)
        animations.StartAnimation(0, _animationQueue[0][1], _callbackPt[_animationQueue[0][0]]);

        //Remove the just started animation from the queue
        _animationQueue.erase(_animationQueue.begin());
    }
}

main.cpp:

Animator animator;

void setup()
{

    animator.init();
}

void loop()
{
    //Put new animation requests in queue and update animations
    animator.run();
}

platformio.ini:

[env:due]
lib_ldf_mode = chain+
platform = atmelsam
board = due
framework = arduino
monitor_speed = 115200
monitor_port = COM16

lib_deps = 
    NeoPixelBus

вызов animations.StartAnimation(0, _animationQueue[0][1], _callbackPt[_animationQueue[0][0]]); не дает ошибок компиляции. Попытка создания экземпляра функций обратного вызова в массиве указателей на функции делает, однако:

значение типа "AnimUpdateCallback (Animator::*)(const AnimationParam &param)" нельзя использовать для инициализации объекта типа "AnimUpdateCallback (*)(const AnimationParam &param)"

Мое основное замешательство:

  • каким должен быть тип данных функций обратного вызова в моем классе (void или AnimUpdateCallback)?

  • почему (const AnimationParam &param) необходимо добавить в конце (*_callbackPt[NUMBER_OF_ANIMATIONS]), в противном случае я получаю ошибку, что типы данных также не совпадают

1 Ответ

1 голос
/ 06 июня 2019

значение типа "AnimUpdateCallback (Animator::*)(const AnimationParam &param)" нельзя использовать для инициализации объекта типа "AnimUpdateCallback (*)(const AnimationParam &param)"

Это правда. Я не вижу код, который вызывает эту ошибку, но, вероятно, вы используете нестатическую функцию-член Animator для инициализации элемента вашего массива. (Является ли это wipeColorAnim функцией члена? Это не объявлено в вопросе.) Поскольку нестатические функции-члены имеют скрытый параметр (указатель this), они несовместимы с сигнатурой с функциями, не являющимися членами. , Если вашей функции-члену не нужен параметр this, объявите его static. (Если это требует this, у вас есть большая проблема дизайна.)

каким должен быть тип данных функций обратного вызова в моем классе (void или AnimUpdateCallback)?

Ну, void не является типом функции, так что я полагаю, что его нет, у вас остается только один выбор ... (Если вы не имели в виду тип возвращаемого значения, а не тип данных? Тип данных будет сигнатура функции, охватывающая как тип возвращаемого значения, так и типы параметров.)

почему (const AnimationParam &param) нужно добавить в конце (*_callbackPt[NUMBER_OF_ANIMATIONS]), в противном случае я получаю сообщение об ошибке, что типы данных также не совпадают

Полагаю, хороший способ объяснить это - посмотреть, что объявят декларации.

 AnimUpdateCallback (*_callbackPt[NUMBER_OF_ANIMATIONS])(const AnimationParam &param);
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- an array of pointers

Самая внутренняя часть - это массив указателей на что-то. Чтобы увидеть тип, на который они указывают, сведите внутреннюю часть к звездочке:

 AnimUpdateCallback (*)(const AnimationParam &param);

Это указатель на функцию, которая принимает один параметр (типа const AnimationParam &) и возвращает значение типа AnimUpdateCallback. Идентификатор "param" здесь излишен.

Без детали на конце, вы просто

 AnimUpdateCallback (*_callbackPt[NUMBER_OF_ANIMATIONS]);
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- an array of pointers

На этот раз указательный тип легче увидеть: AnimUpdateCallback.

Так что в любом случае у вас есть способ получить значение типа AnimUpdateCallback. В первом случае вы должны получить доступ к элементу вашего массива, вызвать функцию, на которую он указывает, и посмотреть возвращаемое значение, например: _callbackPt[0](param). В последнем случае вы просто получите доступ к элементу вашего массива, например: _callbackPt[0]. Правильная форма зависит от того, как вы собираетесь использовать этот массив. (Объявление NeoPixelAnimator напрямую не рассматривается, поэтому я не знаю, что ожидается в качестве параметров для NeoPixelAnimator::StartAnimation().)

...