Stairs/src/stairs.cpp

205 lines
6.0 KiB
C++

#include "stairs.h"
#include <Math.h>
#include <FS.h>
#include "debug.h"
#include "global.h"
const uint16_t PWMCurve[] =
{
0, 10, 11, 12, 12, 13, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 35, 36, 38, 40, 42, 44,
46, 48, 51, 53, 56, 58, 61, 64, 67, 70, 74, 77, 81, 85, 89, 93,
97, 102, 107, 112, 117, 123, 129, 135, 141, 148, 155, 162, 169, 177, 186, 194,
203, 213, 222, 233, 243, 254, 266, 278, 291, 304, 318, 332, 347, 362, 378, 395,
412, 430, 449, 468, 488, 509, 531, 553, 576, 600, 625, 651, 677, 704, 733, 762,
792, 823, 854, 887, 920, 955, 990, 1026, 1063, 1101, 1140, 1180, 1220, 1261, 1303, 1346,
1389, 1433, 1478, 1523, 1569, 1615, 1662, 1709, 1757, 1805, 1853, 1901, 1950, 1999, 2048, 2096,
2145, 2194, 2242, 2290, 2338, 2386, 2433, 2480, 2526, 2572, 2617, 2662, 2706, 2749, 2792, 2834,
2875, 2915, 2955, 2994, 3032, 3069, 3105, 3140, 3175, 3208, 3241, 3272, 3303, 3333, 3362, 3391,
3418, 3444, 3470, 3495, 3519, 3542, 3564, 3586, 3607, 3627, 3646, 3665, 3683, 3700, 3717, 3733,
3748, 3763, 3777, 3791, 3804, 3817, 3829, 3841, 3852, 3862, 3873, 3882, 3892, 3901, 3909, 3918,
3926, 3933, 3940, 3947, 3954, 3960, 3966, 3972, 3978, 3983, 3988, 3993, 3998, 4002, 4006, 4010,
4014, 4018, 4021, 4025, 4028, 4031, 4034, 4037, 4039, 4042, 4044, 4047, 4049, 4051, 4053, 4055,
4057, 4059, 4060, 4062, 4063, 4065, 4066, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076,
4077, 4078, 4079, 4079, 4080, 4081, 4082, 4082, 4083, 4083, 4084, 4084, 4085, 4085, 4090, 4095
};
const float LinearFactor = 4095.0f / 255.0f;
void Stairs::init(PCA9685* pwmDriver)
{
mPWMDriver = pwmDriver;
memset(&mStep[0], 0, sizeof(mStep));
}
uint8_t Stairs::ease(uint8_t startValue, uint8_t targetValue, uint16_t transitionTime, uint16_t elapsedTime)
{
bool up = targetValue > startValue;
uint16_t diff = up ? targetValue - startValue : startValue - targetValue;
uint16_t delta = (diff * elapsedTime) / transitionTime;
int16_t currentValue = up ? startValue + delta : startValue - delta;
if (currentValue < 0) currentValue = 0;
if (currentValue > 255) currentValue = 255;
return currentValue;
}
inline void Stairs::updateCurrentValue(Step* stepState)
{
int32_t stepElapsedTime = -stepState->startTime;
stepState->currentValue = ease(stepState->startValue, stepState->targetValue, stepState->remainingTime + stepElapsedTime, stepElapsedTime);
}
inline void Stairs::applyCurrentValue(uint8_t step)
{
mPWMDriver->setPWM(step, this->getPWMValue(step, mStep[step].currentValue));
}
void Stairs::tick()
{
if (!mTick) return;
uint32_t elapsedTime = mLastTransitionTime != 0 ? currentTime - mLastTransitionTime : 0;
if (!elapsedTime) return;
mLastTransitionTime = currentTime;
mTick = false;
for (uint8_t step = 0; step < stepsSettings->count(); step++)
{
Step* stepState = &mStep[step];
if (stepState->currentValue != stepState->targetValue)
{
// If there is a startup delay request, wait for it first
if (stepState->startTime > 0)
{
stepState->startTime -= elapsedTime;
if (stepState->startTime < 0)
{
if (stepState->remainingTime > -stepState->startTime)
{
// Shift the remaining time equally
stepState->remainingTime += stepState->startTime;
updateCurrentValue(stepState);
mTick = true;
}
else
{
// End of the transition
stepState->remainingTime = 0;
stepState->currentValue = stepState->targetValue;
}
applyCurrentValue(step);
}
}
else if (elapsedTime >= stepState->remainingTime)
{
// End of the transition
stepState->remainingTime = 0;
stepState->currentValue = stepState->targetValue;
applyCurrentValue(step);
}
else
{
stepState->startTime -= elapsedTime;
stepState->remainingTime -= elapsedTime;
updateCurrentValue(stepState);
applyCurrentValue(step);
mTick = true;
}
}
}
if (!mTick)
mLastTransitionTime = 0;
}
uint8_t Stairs::get(uint8_t step, bool target)
{
if (step >= MaxStepCount) return 0;
return target ? mStep[step].targetValue : mStep[step].currentValue;
}
void Stairs::set(uint8_t step, uint8_t brightness, uint16_t transitionTime, uint16_t startTime)
{
_d("Stairs :: set step = "); _d(step);
_d(", brightness = "); _d(brightness);
_d(", transitionTime = "); _d(transitionTime);
_d(", startTime = "); _dln(startTime);
if (step >= MaxStepCount) return;
if (mStep[step].currentValue == brightness)
return;
mStep[step].targetValue = brightness;
if (transitionTime > 0)
{
mStep[step].startValue = mStep[step].currentValue;
mStep[step].startTime = startTime;
mStep[step].remainingTime = transitionTime;
if (!mLastTransitionTime)
mLastTransitionTime = currentTime;
mTick = true;
}
else
{
mStep[step].currentValue = brightness;
applyCurrentValue(step);
}
}
void Stairs::setAll(uint8_t brightness, uint16_t transitionTime, uint16_t startTime)
{
for (uint8_t step = 0; step < stepsSettings->count(); step++)
set(step, brightness, transitionTime, startTime);
}
uint16_t Stairs::getPWMValue(uint8_t step, uint8_t brightness)
{
//_d("Stairs :: Getting PWM value for step "); _d(step); _d(", brightness "); _dln(brightness);
if (brightness == 0 || brightness == 255)
{
//_dln("Stairs :: Full on/off, returning input");
return brightness == 0 ? 0 : 4095;
}
uint16_t pwmValue;
if (stepsSettings->useCurve())
{
//_dln("Stairs :: Using curve");
pwmValue = PWMCurve[brightness] + stepsSettings->curveShift(step);
}
else
{
//_dln("Stairs :: Not using curve");
pwmValue = brightness * LinearFactor;
}
//_d("Stairs :: Output: "); _dln(pwmValue);
return pwmValue;
}