add a writing animation of words

This commit is contained in:
lukas 2022-02-01 00:51:31 +01:00
parent e0cbb4acb6
commit 3c22de49c7
6 changed files with 172 additions and 33 deletions

View File

@ -30,13 +30,21 @@ void Clock::turnOn() {
} }
void Clock::paintAlwaysOnLeds() { void Clock::paintAlwaysOnLeds() {
printWord(types::es, Adafruit_NeoPixel::Color(255, 255, 0)); addque.push_back(Word(types::es, 0xFFFF00));
printWord(types::ist, Adafruit_NeoPixel::Color(255, 0, 255)); addque.push_back(Word(types::ist, 0xFF00FF));
} }
void Clock::printWord(const std::vector<uint8_t>& word, uint32_t color) { void Clock::printWord(const std::vector<uint8_t>& word, uint32_t color, bool highlightfirst) {
for (const uint8_t i : word) { uint r = (color >> 16) & 0xFF;
strip.setPixelColor(i, color); uint g = (color >> 8) & 0xFF;
uint b = (color)&0xFF;
for (const uint8_t& i : word) {
strip.setPixelColor(
i,
!highlightfirst || (&i == &word.back())
? color
: (((r > 200 ? r - 200 : r) << 16) | ((g > 200 ? g - 200 : g) << 8) | (b > 200 ? b - 200 : b)));
} }
} }
@ -50,9 +58,14 @@ void Clock::refreshTime() {
return; return;
} }
if (animator.animationActive()) {
animator.stopLoadAnimation(); animator.stopLoadAnimation();
strip.clear(); strip.clear();
// only add on first time iteration
paintAlwaysOnLeds();
}
tm* loctime = localtime(&now); tm* loctime = localtime(&now);
const uint8_t hour = loctime->tm_hour; const uint8_t hour = loctime->tm_hour;
@ -65,18 +78,17 @@ void Clock::refreshTime() {
strip.setBrightness(DAYBRIGHTNESS); strip.setBrightness(DAYBRIGHTNESS);
} }
paintAlwaysOnLeds();
setTime(hour, minute, this->twentyAfterSyntax, this->clockAlwaysOn); setTime(hour, minute, this->twentyAfterSyntax, this->clockAlwaysOn);
strip.show(); strip.show();
Serial.printf("Time now: %uh %uM\n", hour, minute); Serial.printf("Time now: %uh %uM\n", hour, minute);
} }
void Clock::setTime(uint8_t hour, uint8_t minute, bool twentyAfterSyntax, bool alwaysClockWord) { void Clock::setTime(uint8_t hour, uint8_t minute, bool twas, bool alwaysClockWord) {
const uint8_t minuteselector = minute / 5; const uint8_t minuteselector = minute / 5;
// if minuteselector >= 4 +1 to hour // if minuteselector >= 4 +1 to hour
if (twentyAfterSyntax ? minuteselector >= 5 : minuteselector >= 4) if (twas ? minuteselector >= 5 : minuteselector >= 4)
hour++; hour++;
// convert to 12h format // convert to 12h format
@ -98,24 +110,39 @@ void Clock::setTime(uint8_t hour, uint8_t minute, bool twentyAfterSyntax, bool a
: hour == 0 || hour == 12 ? types::zwoelf : hour == 0 || hour == 12 ? types::zwoelf
: hourWord; : hourWord;
printWord(hourWord, Adafruit_NeoPixel::Color(0, 255, 255)); if (oldhourWord != hourWord) {
addque.push_back(Word(hourWord, 0x00FFFF));
delque.push_back(Word(oldhourWord, 0x00FFFF));
oldhourWord = hourWord;
}
// printWord(hourWord, Adafruit_NeoPixel::Color(0, 255, 255));
// print the minute words and the corresponding after/before half words // print the minute words and the corresponding after/before half words
printMinutes(minuteselector, twentyAfterSyntax); printMinutes(minuteselector, twas);
// uhr // uhr
if (minuteselector == 0 || alwaysClockWord) bool uhractive = minuteselector == 0 || alwaysClockWord;
printWord(types::uhr, Adafruit_NeoPixel::Color(255, 0, 0));
if (oldUhrActive != uhractive) {
const Word wrd = Word(types::uhr, 0xFF0000);
(uhractive ? addque : delque).push_back(wrd);
oldUhrActive = uhractive;
}
performWordTransition();
} }
void Clock::printMinutes(uint8_t minuteSelector, bool twentyAfterSyntax) { void Clock::printMinutes(uint8_t minuteSelector, bool twas) {
// fuenf / zehn / viertl word // fuenf / zehn / viertl word
std::vector<uint8_t> minuteWord; std::vector<uint8_t> minuteWord, vornachWord;
bool halfActive = false;
if (minuteSelector == 1 || minuteSelector == 5 || minuteSelector == 7 || minuteSelector == 11) { if (minuteSelector == 1 || minuteSelector == 5 || minuteSelector == 7 || minuteSelector == 11) {
minuteWord = types::fuenf; minuteWord = types::fuenf;
} else if (minuteSelector == 2 || minuteSelector == 4 || minuteSelector == 8 || minuteSelector == 10) { } else if (minuteSelector == 2 || minuteSelector == 4 || minuteSelector == 8 || minuteSelector == 10) {
// check if we use the twenty after syntax // check if we use the twenty after syntax
if ((minuteSelector == 4 || minuteSelector == 8) && twentyAfterSyntax) if ((minuteSelector == 4 || minuteSelector == 8) && twas)
minuteWord = types::zwanzig; minuteWord = types::zwanzig;
else else
minuteWord = types::zehn; minuteWord = types::zehn;
@ -126,34 +153,45 @@ void Clock::printMinutes(uint8_t minuteSelector, bool twentyAfterSyntax) {
else if (minuteSelector == 6) else if (minuteSelector == 6)
minuteWord = types::halb; minuteWord = types::halb;
printWord(minuteWord, Adafruit_NeoPixel::Color(0, 255, 0)); if (oldminuteWord != minuteWord) {
addque.push_back(Word(minuteWord, 0x00FF00));
delque.push_back(Word(oldminuteWord, 0x00FF00));
oldminuteWord = minuteWord;
}
// vor / nach // vor / nach
std::vector<uint8_t> vornachWord;
if (minuteSelector == 1 || minuteSelector == 2 || minuteSelector == 3 || if (minuteSelector == 1 || minuteSelector == 2 || minuteSelector == 3 ||
((minuteSelector == 8) && ((minuteSelector == 8) && !twas) || // check if twentyafter syntax is enabled - if not display the the after
!twentyAfterSyntax) || // check if twentyafter syntax is enabled - if not display the the after
minuteSelector == 7 || minuteSelector == 7 ||
((minuteSelector == 4) && ((minuteSelector == 4) && twas)) // check if twentyafter syntax is enabled - if yes display the the after
twentyAfterSyntax)) // check if twentyafter syntax is enabled - if yes display the the after
vornachWord = types::nach; vornachWord = types::nach;
else if (minuteSelector == 5 || else if (minuteSelector == 5 ||
((minuteSelector == 4) && !twentyAfterSyntax) // check if twentyafter enabled if not -- display vor ((minuteSelector == 4) && !twas) // check if twentyafter enabled if not -- display vor
|| minuteSelector == 10 || minuteSelector == 11 || || minuteSelector == 10 || minuteSelector == 11 ||
((minuteSelector == 8) && twentyAfterSyntax)) // check if twentyafter enabled if yess -- display vor ((minuteSelector == 8) && twas)) // check if twentyafter enabled if yess -- display vor
vornachWord = types::vor; vornachWord = types::vor;
printWord(vornachWord, Adafruit_NeoPixel::Color(255, 255, 255));
if (oldvornachWord != vornachWord) {
addque.push_back(Word(vornachWord, 0xFFFFFF));
delque.push_back(Word(oldvornachWord, 0xFFFFFF));
oldvornachWord = vornachWord;
}
// halb // halb
if (minuteSelector >= 4 && minuteSelector <= 8) { if (minuteSelector >= 4 && minuteSelector <= 8) {
// only 3 times if twentyafter syntax is on // only 3 times if twentyafter syntax is on
if (!twentyAfterSyntax || (minuteSelector >= 5 && minuteSelector <= 7)) if (!twas || (minuteSelector >= 5 && minuteSelector <= 7))
printWord(types::halb, Adafruit_NeoPixel::Color(255, 0, 0)); halfActive = true;
}
if (oldhalfActive != halfActive) {
(halfActive ? addque : delque).push_back(Word(types::halb, 0xFF0000));
oldhalfActive = halfActive;
} }
} }
void Clock::useTwentyAfterSyntax(bool twentyAFterSyntax) { void Clock::useTwentyAfterSyntax(bool twas) {
this->twentyAfterSyntax = twentyAFterSyntax; this->twentyAfterSyntax = twas;
} }
void Clock::useAlwaysOnUhrSyntax(bool alwaysOnUhr) { void Clock::useAlwaysOnUhrSyntax(bool alwaysOnUhr) {
@ -164,3 +202,60 @@ void Clock::update() {
if (refreshTicker.active()) if (refreshTicker.active())
this->refreshTime(); this->refreshTime();
} }
int it = 0;
void Clock::performWordTransition() {
if (addque.empty() && delque.empty())
return;
int maxdels = 0;
for (const Word& el : delque) {
if (el.wrd.size() > maxdels) {
maxdels = el.wrd.size();
}
}
int maxadds = 0;
for (const Word& el : addque) {
if (el.wrd.size() > maxadds) {
maxadds = el.wrd.size();
}
}
// const uint iterationcount = maxdels + maxadds;
if (!transitionTicker.active()) {
transitionTicker.attach_ms(150, [this, maxdels, maxadds]() {
if (it <= maxdels) {
for (Word word : delque) {
if (word.wrd.size() < it)
continue;
this->printWord(word.wrd, 0x0, false);
this->printWord({word.wrd.begin(), word.wrd.end() - it}, word.color, false);
}
this->strip.show();
} else if (it - maxdels <= maxadds) {
// we are modding the endword
int idx = it - maxdels;
for (Word word : addque) {
if (word.wrd.size() < idx)
continue;
this->printWord(word.wrd, 0x0, false);
this->printWord({word.wrd.begin(), word.wrd.begin() + idx}, word.color, idx < word.wrd.size());
}
this->strip.show();
} else {
addque.clear();
delque.clear();
transitionTicker.detach();
it = 0;
}
it++;
});
}
}

View File

@ -8,8 +8,8 @@
#include "Arduino.h" #include "Arduino.h"
#include <Ticker.h> #include <Ticker.h>
#include "Adafruit_NeoPixel.h" #include "Adafruit_NeoPixel.h"
#include "Arduino.h"
#include "LoadAnimator.h" #include "LoadAnimator.h"
#include "Word.h"
// define the strip length of the wordclock // define the strip length of the wordclock
#define NUMPIXELS 108 #define NUMPIXELS 108
@ -24,6 +24,13 @@ class Clock {
Adafruit_NeoPixel strip{}; Adafruit_NeoPixel strip{};
LoadAnimator animator; LoadAnimator animator;
Ticker refreshTicker; Ticker refreshTicker;
Ticker transitionTicker;
std::vector<Word> delque;
std::vector<Word> addque;
std::vector<uint8_t> oldminuteWord, oldvornachWord, oldhourWord;
bool oldhalfActive, oldUhrActive;
bool twentyAfterSyntax; bool twentyAfterSyntax;
bool clockAlwaysOn; bool clockAlwaysOn;
@ -33,12 +40,15 @@ class Clock {
*/ */
void paintAlwaysOnLeds(); void paintAlwaysOnLeds();
std::vector<uint8_t> minuteBefore;
void performWordTransition();
/** /**
* paint a specific word * paint a specific word
* @param word word pointer to print * @param word word pointer to print
* @param color the color in which to print it * @param color the color in which to print it
*/ */
void printWord(const std::vector<uint8_t>& word, uint32_t color); void printWord(const std::vector<uint8_t>& word, uint32_t color, bool highlightfirst);
/** /**
* logic to print the correct minute word and its corresponding wods * logic to print the correct minute word and its corresponding wods

View File

@ -44,3 +44,6 @@ void LoadAnimator::animationStep() {
nroo = nro; nroo = nro;
nro = nr; nro = nr;
} }
bool LoadAnimator::animationActive() {
return timer.active();
}

View File

@ -32,6 +32,8 @@ class LoadAnimator {
* stop the animation * stop the animation
*/ */
void stopLoadAnimation(); void stopLoadAnimation();
bool animationActive();
}; };
#endif // LEDSTRIPINTERFACE_LOADANIMATOR_H #endif // LEDSTRIPINTERFACE_LOADANIMATOR_H

10
src/Word.cpp Normal file
View File

@ -0,0 +1,10 @@
//
// Created by lukas on 31.01.22.
//
#include "Word.h"
#include <utility>
Word::Word(std::vector<uint8_t> wrd, uint32_t color) : wrd(std::move(wrd)), color(color) {
}

19
src/Word.h Normal file
View File

@ -0,0 +1,19 @@
//
// Created by lukas on 31.01.22.
//
#ifndef LEDSTRIPINTERFACE_WORD_H
#define LEDSTRIPINTERFACE_WORD_H
#include <Ticker.h>
#include "Arduino.h"
class Word {
public:
std::vector<uint8_t> wrd;
uint32_t color;
Word(std::vector<uint8_t> wrd, uint32_t color);
};
#endif // LEDSTRIPINTERFACE_WORD_H