diff --git a/SSD1306Ui.cpp b/SSD1306Ui.cpp index bcdb751355cef4eb88932f8f8538bb0695ae5b0f..198e3d2e11744ba22b7014d657516e1a92c4cf8f 100644 --- a/SSD1306Ui.cpp +++ b/SSD1306Ui.cpp @@ -10,17 +10,22 @@ void SSD1306Ui::init() { } void SSD1306Ui::setTargetFPS(byte fps){ + int oldInterval = this->updateInterval; this->updateInterval = ((float) 1.0 / (float) fps) * 1000; - Serial.println(this->updateInterval); + + // Calculate new ticksPerFrame + float changeRatio = oldInterval / this->updateInterval; + this->ticksPerFrame *= changeRatio; + this->ticksPerTransition *= changeRatio; } // -/------ Automatic controll ------\- void SSD1306Ui::enableAutoTransition(){ - autoTransition = true; + this->autoTransition = true; } void SSD1306Ui::disableAutoTransition(){ - autoTransition = false; + this->autoTransition = false; } void SSD1306Ui::setAutoTransitionForwards(){ this->frameTransitionDirection = 1; @@ -49,22 +54,22 @@ void SSD1306Ui::setActiveSymbole(const char* symbole) { this->dirty = true; } void SSD1306Ui::setInactiveSymbole(const char* symbole) { - this->inactiveSymbole = symbole; + this->inactiveSymbole = symbole; this->dirty = true; } // -/----- Frame settings -----\- -void SSD1306Ui::setFrameAnimation(AnimationDirection dir) { +void SSD1306Ui::setFrameAnimation(AnimationDirection dir) { this->frameAnimationDirection = dir; } -void SSD1306Ui::setFrames(bool (*frameFunctions[])(SSD1306 *display, int x, int y), int frameCount) { +void SSD1306Ui::setFrames(FrameCallback* frameFunctions, int frameCount) { this->frameCount = frameCount; this->frameFunctions = frameFunctions; } // -/----- Overlays ------\- -void SSD1306Ui::setOverlays(bool (*overlayFunctions[])(SSD1306 *display), int overlayCount){ +void SSD1306Ui::setOverlays(OverlayCallback* overlayFunctions, int overlayCount){ this->overlayCount = overlayCount; this->overlayFunctions = overlayFunctions; } @@ -72,67 +77,63 @@ void SSD1306Ui::setOverlays(bool (*overlayFunctions[])(SSD1306 *display), int ov // -/----- Manuel control -----\- void SSD1306Ui::nextFrame() { - this->frameState = IN_TRANSITION; - this->ticksSinceLastStateSwitch = 0; + this->state.frameState = IN_TRANSITION; + this->state.ticksSinceLastStateSwitch = 0; this->frameTransitionDirection = 1; } void SSD1306Ui::previousFrame() { - this->frameState = IN_TRANSITION; - this->ticksSinceLastStateSwitch = 0; + this->state.frameState = IN_TRANSITION; + this->state.ticksSinceLastStateSwitch = 0; this->frameTransitionDirection = -1; } // -/----- State information -----\- -FrameState SSD1306Ui::getFrameState(){ - return this->frameState; -} -int SSD1306Ui::getCurrentFrame(){ - return this->currentFrame; +SSD1306UiState SSD1306Ui::getUiState(){ + return this->state; } int SSD1306Ui::update(){ - int timeBudget = this->updateInterval - (millis() - this->lastUpdate); + int timeBudget = this->updateInterval - (millis() - this->state.lastUpdate); if ( timeBudget <= 0) { - // Implement frame skipping to ensure time budget is keept - if (this->autoTransition && this->lastUpdate != 0) this->ticksSinceLastStateSwitch += abs(timeBudget) / this->updateInterval; - - this->lastUpdate = millis(); + if (this->autoTransition && this->state.lastUpdate != 0) this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval); + + this->state.lastUpdate = millis(); this->tick(); - } + } return timeBudget; } void SSD1306Ui::tick() { - this->ticksSinceLastStateSwitch++; + this->state.ticksSinceLastStateSwitch++; - switch (this->frameState) { + switch (this->state.frameState) { case IN_TRANSITION: this->dirty = true; - if (this->ticksSinceLastStateSwitch >= this->ticksPerTransition){ - this->frameState = FIXED; - this->currentFrame = getNextFrameNumber(); - this->ticksSinceLastStateSwitch = 0; + if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition){ + this->state.frameState = FIXED; + this->state.currentFrame = getNextFrameNumber(); + this->state.ticksSinceLastStateSwitch = 0; } break; case FIXED: - if (this->ticksSinceLastStateSwitch >= this->ticksPerFrame){ + if (this->state.ticksSinceLastStateSwitch >= this->ticksPerFrame){ if (this->autoTransition){ - this->frameState = IN_TRANSITION; + this->state.frameState = IN_TRANSITION; this->dirty = true; } - this->ticksSinceLastStateSwitch = 0; + this->state.ticksSinceLastStateSwitch = 0; } break; } - + if (this->dirty) { this->dirty = false; this->display->clear(); - this->drawIndicator(); + this->drawIndicator(); this->drawFrame(); this->drawOverlays(); this->display->display(); @@ -140,9 +141,9 @@ void SSD1306Ui::tick() { } void SSD1306Ui::drawFrame(){ - switch (this->frameState){ + switch (this->state.frameState){ case IN_TRANSITION: { - float progress = (float) this->ticksSinceLastStateSwitch / (float) this->ticksPerTransition; + float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition; int x, y, x1, y1; switch(this->frameAnimationDirection){ case SLIDE_LEFT: @@ -175,36 +176,36 @@ void SSD1306Ui::drawFrame(){ int dir = frameTransitionDirection >= 0 ? 1 : -1; x *= dir; y *= dir; x1 *= dir; y1 *= dir; - this->dirty |= (*this->frameFunctions[this->currentFrame])(this->display, x, y); - this->dirty |= (*this->frameFunctions[this->getNextFrameNumber()])(this->display, x1, y1); + this->dirty |= (this->frameFunctions[this->state.currentFrame])(this->display, &this->state, x, y); + this->dirty |= (this->frameFunctions[this->getNextFrameNumber()])(this->display, &this->state, x1, y1); break; } case FIXED: - this->dirty |= (*this->frameFunctions[this->currentFrame])(this->display, 0, 0); + this->dirty |= (this->frameFunctions[this->state.currentFrame])(this->display, &this->state, 0, 0); break; } } void SSD1306Ui::drawIndicator() { - byte posOfCurrentFrame; - + byte posOfCurrentFrame; + switch (this->indicatorDirection){ case LEFT_RIGHT: - posOfCurrentFrame = this->currentFrame; + posOfCurrentFrame = this->state.currentFrame; break; case RIGHT_LEFT: - posOfCurrentFrame = (this->frameCount - 1) - this->currentFrame; + posOfCurrentFrame = (this->frameCount - 1) - this->state.currentFrame; break; } - + for (byte i = 0; i < this->frameCount; i++) { - - const char *xbm; - + + const char *image; + if (posOfCurrentFrame == i) { - xbm = this->activeSymbole; + image = this->activeSymbole; } else { - xbm = this->inactiveSymbole; + image = this->inactiveSymbole; } int x,y; @@ -226,24 +227,23 @@ void SSD1306Ui::drawIndicator() { y = 32 - (12 * frameCount / 2) + 12 * i; break; } - - this->display->drawXbm(x, y, 8, 8, xbm); - } + + this->display->drawFastImage(x, y, 8, 8, image); + } } void SSD1306Ui::drawOverlays() { for (int i=0;i<this->overlayCount;i++){ - this->dirty |= (*this->overlayFunctions[i])(this->display); + this->dirty |= (this->overlayFunctions[i])(this->display, &this->state); } } int SSD1306Ui::getNextFrameNumber(){ - int nextFrame = (this->currentFrame + this->frameTransitionDirection) % this->frameCount; + int nextFrame = (this->state.currentFrame + this->frameTransitionDirection) % this->frameCount; if (nextFrame < 0){ nextFrame = this->frameCount + nextFrame; } - return nextFrame; + return nextFrame; } - diff --git a/SSD1306Ui.h b/SSD1306Ui.h index e43f8980c37b5d76b67f1777d77129204a216253..703d47b6bd20551ddd8415abe711b4c63f35a32a 100644 --- a/SSD1306Ui.h +++ b/SSD1306Ui.h @@ -60,6 +60,19 @@ const char ANIMATION_inactiveSymbole[] PROGMEM = { 0x00, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x00 }; + +// Structure of the UiState +struct SSD1306UiState { + int lastUpdate = 0; + int ticksSinceLastStateSwitch = 0; + + FrameState frameState = FIXED; + int currentFrame = 0; +}; + +typedef bool (*FrameCallback)(SSD1306 *display, SSD1306UiState* state, int x, int y); +typedef bool (*OverlayCallback)(SSD1306 *display, SSD1306UiState* state); + class SSD1306Ui { private: SSD1306 *display; @@ -76,29 +89,26 @@ class SSD1306Ui { // Values for the Frames AnimationDirection frameAnimationDirection = SLIDE_RIGHT; - FrameState frameState = FIXED; int frameTransitionDirection = 1; - int ticksPerFrame = 313; // ~ 5000ms at 60 FPS - int ticksPerTransition = 32; // ~ 500ms at 60 FPS - int ticksSinceLastStateSwitch = 0; - int currentFrame = 0; + int ticksPerFrame = 151; // ~ 5000ms at 30 FPS + int ticksPerTransition = 15; // ~ 500ms at 30 FPS bool autoTransition = true; - bool (**frameFunctions)(SSD1306 *display, int x, int y); + FrameCallback* frameFunctions; int frameCount = 0; // Values for Overlays - bool (**overlayFunctions)(SSD1306 *display); + OverlayCallback* overlayFunctions; int overlayCount = 0; + // UI State + SSD1306UiState state; // Bookeeping for update - int updateInterval = 16; - unsigned long lastUpdate = 0; - + int updateInterval = 33; int getNextFrameNumber(); void drawIndicator(); @@ -147,7 +157,7 @@ class SSD1306Ui { */ void setTimePerTransition(int time); - // Customize Indicator Position and style + // Customize indicator position and style /** * Set the position of the indicator bar. */ @@ -178,25 +188,22 @@ class SSD1306Ui { /** * Add frame drawing functions */ - void setFrames(bool (*frameFunctions[])(SSD1306 *display, int x, int y), int frameCount); + void setFrames(FrameCallback* frameFunctions, int frameCount); // Overlay /** * Add overlays drawing functions that are draw independent of the Frames */ - void setOverlays(bool (*overlayFunctions[])(SSD1306 *display), int overlayCount); + void setOverlays(OverlayCallback* overlayFunctions, int overlayCount); // Manuell Controll void nextFrame(); void previousFrame(); // State Info - FrameState getFrameState(); - int getCurrentFrame(); - + SSD1306UiState getUiState(); int update(); }; -