Skip to content

File evamKickDecor.h

File List > src > evamKickDecor.h

Go to the documentation of this file

#pragma once

#include <Arduino.h>
#include <evaTickable.h>

using namespace eva;

namespace evam
{
    constexpr unsigned short kDefaultKickDurationMs = 20;
    constexpr signed short kDefaultKickPower = 1000;
    constexpr signed short kMaxKickPower = 1000;

    struct KickConfig {
        unsigned short duration;
        signed short power;

        KickConfig(unsigned short duration, signed short power) : duration(duration > 0 ? duration : kDefaultKickDurationMs), power(constrain(power, 0, kMaxKickPower)) {}
    };

    template <class TMotor, 
              unsigned short tDefaultKickDurationMs = kDefaultKickDurationMs, 
              signed short tDefaultKickPower = kDefaultKickPower>
    class KickDecor : public virtual Tickable, public TMotor
    {
        static_assert(tDefaultKickDurationMs > 0, "tDefaultKickDurationMs must be > 0");
        static_assert(tDefaultKickPower > 0 && tDefaultKickPower <= kMaxKickPower, "tDefaultKickPower out of range");

    private:
        KickConfig mConfig;

        signed short mTargetSpeed = 0;
        unsigned long mHoldingStartedAt = 0;

        signed short calculateKickPower(signed short aValue) const
        {
            if ((mTargetSpeed <= 0) && (aValue > 0))
                return mConfig.power;

            if ((mTargetSpeed >= 0) && (aValue < 0))
                return -mConfig.power;

            return 0;
        }

        void tick() override
        {
            if (!mHoldingStartedAt)
                return;

            if (millis() - mHoldingStartedAt < mConfig.duration)
                return;

            TMotor::Go(mTargetSpeed);
            mHoldingStartedAt = 0;
        }

    public:
        KickDecor() : mConfig(tDefaultKickDurationMs, tDefaultKickPower) {}

        template<typename... Args>
        KickDecor(KickConfig config, Args... args) : mConfig(config), TMotor(args...) {}

        void SetupKickstart(unsigned short duration, signed short power)
        {
            SetKickDuration(duration);
            SetKickPower(power);
        }

        void SetKickDuration(unsigned short aValue)
        {
            if (aValue > 0)
                mConfig.duration = aValue;
        }

        unsigned short GetKickDuration() const
        {
            return mConfig.duration;
        }

        void SetKickPower(signed short aValue)
        {
            mConfig.power = constrain(aValue, 0, 1000);
        }

        signed short GetKickPower() const
        {
            return mConfig.power;
        }

        void Go(signed short aValue)
        {
            signed short needKick = calculateKickPower(aValue);
            mTargetSpeed = aValue;

            if (needKick)
            {
                TMotor::Go(needKick);
                mHoldingStartedAt = millis();
                return;
            }

            if (mHoldingStartedAt)
                return;

            TMotor::Go(aValue);
        }
    };
}