diff --git a/workspace/TS100/Core/Inc/OLED.hpp b/workspace/TS100/Core/Inc/OLED.hpp index 381fd9f0..2bbd23a2 100644 --- a/workspace/TS100/Core/Inc/OLED.hpp +++ b/workspace/TS100/Core/Inc/OLED.hpp @@ -78,7 +78,7 @@ public: // Draws a number at the current cursor location // Clears the buffer static void clearScreen() { - memset(&screenBuffer[FRAMEBUFFER_START], 0, OLED_WIDTH * 2); + memset(firstStripPtr, 0, OLED_WIDTH * 2); } // Draws the battery level symbol static void drawBattery(uint8_t state) { @@ -99,6 +99,10 @@ public: static void drawFilledRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, bool clear); static void drawHeatSymbol(uint8_t state); + static void presentSecondScreenBufferAnimatedBack(); + static void presentSecondScreenBufferAnimated(); + static void use_first_buffer(); + static void use_second_buffer(); private: static void drawChar(char c); // Draw a character to a specific location static const uint8_t* currentFont;// Pointer to the current font used for rendering to the buffer @@ -110,6 +114,7 @@ private: static int16_t cursor_x, cursor_y; static uint8_t displayOffset; static uint8_t screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer + static uint8_t secondFrameBuffer[OLED_WIDTH * 2]; // The second frame buffer }; #endif /* OLED_HPP_ */ diff --git a/workspace/TS100/Core/Src/OLED.cpp b/workspace/TS100/Core/Src/OLED.cpp index bef541d1..00e35974 100644 --- a/workspace/TS100/Core/Src/OLED.cpp +++ b/workspace/TS100/Core/Src/OLED.cpp @@ -24,6 +24,7 @@ uint8_t OLED::fontWidth, OLED::fontHeight; int16_t OLED::cursor_x, OLED::cursor_y; uint8_t OLED::displayOffset; uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer +uint8_t OLED::secondFrameBuffer[OLED_WIDTH * 2]; // The second frame buffer /*Setup params for the OLED screen*/ /*http://www.displayfuture.com/Display/datasheet/controller/SSD1307.pdf*/ @@ -85,6 +86,16 @@ void OLED::initialize() { sizeof(OLED_Setup_Array)); } +void OLED::use_first_buffer() { + firstStripPtr = &screenBuffer[FRAMEBUFFER_START]; + secondStripPtr = &screenBuffer[FRAMEBUFFER_START + OLED_WIDTH]; +} + +void OLED::use_second_buffer() { + firstStripPtr = &secondFrameBuffer[0]; + secondStripPtr = &secondFrameBuffer[OLED_WIDTH]; +} + /* * Prints a char to the screen. * UTF font handling is done using the two input chars. @@ -106,6 +117,74 @@ void OLED::drawChar(char c) { cursor_x += fontWidth; } +void OLED::presentSecondScreenBufferAnimatedBack() { + OLED::use_first_buffer(); + + uint32_t totalDuration = 50; + + uint32_t duration = 0; + uint32_t start = xTaskGetTickCount(); + uint8_t offset = 0; + while (duration <= totalDuration) + { + duration = xTaskGetTickCount() - start; + + uint8_t progress = (duration * OLED_WIDTH) / totalDuration; + + for (uint8_t i = OLED_WIDTH - 1; i > progress; i--) { + firstStripPtr[i] = firstStripPtr[(i - progress) + offset]; + secondStripPtr[i] = secondStripPtr[(i - progress) + offset]; + } + + offset = progress; + + uint8_t *firstBackStripPtr = &secondFrameBuffer[0]; + uint8_t *secondBackStripPtr = &secondFrameBuffer[OLED_WIDTH]; + + for (uint8_t i = 0; i < progress; i++) { + firstStripPtr[i] = firstBackStripPtr[(i - progress) + OLED_WIDTH]; + secondStripPtr[i] = secondBackStripPtr[(i - progress) + OLED_WIDTH]; + } + + refresh(); + osDelay(40); + } +} + +void OLED::presentSecondScreenBufferAnimated() { + OLED::use_first_buffer(); + + uint32_t totalDuration = 50; + + uint32_t duration = 0; + uint32_t start = xTaskGetTickCount(); + uint8_t offset = 0; + while (duration < totalDuration) + { + duration = xTaskGetTickCount() - start; + + uint8_t progress = (duration * OLED_WIDTH) / totalDuration; + + for (uint8_t i = 0; i < OLED_WIDTH - progress; i++) { + firstStripPtr[i] = firstStripPtr[i + progress - offset]; + secondStripPtr[i] = secondStripPtr[i + progress - offset]; + } + + offset = progress; + + uint8_t *firstBackStripPtr = &secondFrameBuffer[0]; + uint8_t *secondBackStripPtr = &secondFrameBuffer[OLED_WIDTH]; + + for (uint8_t i = OLED_WIDTH - progress; i < OLED_WIDTH; i++) { + firstStripPtr[i] = firstBackStripPtr[i - (OLED_WIDTH - progress)]; + secondStripPtr[i] = secondBackStripPtr[i - (OLED_WIDTH - progress)]; + } + + refresh(); + osDelay(40); + } +} + void OLED::setRotation(bool leftHanded) { #ifdef MODEL_TS80 leftHanded = !leftHanded; diff --git a/workspace/TS100/Core/Src/gui.cpp b/workspace/TS100/Core/Src/gui.cpp index 42834655..99cdcd4f 100644 --- a/workspace/TS100/Core/Src/gui.cpp +++ b/workspace/TS100/Core/Src/gui.cpp @@ -823,6 +823,15 @@ void gui_Menu(const menuitem *menu) { int16_t lastOffset = -1; bool lcdRefresh = true; ButtonState lastButtonState = BUTTON_NONE; + + if (menu[currentScreen].draw.func != NULL) { + OLED::use_second_buffer(); + OLED::setFont(0); + OLED::setCursor(0, 0); + OLED::clearScreen(); + menu[currentScreen].draw.func(); + OLED::presentSecondScreenBufferAnimated(); + } while ((menu[currentScreen].draw.func != NULL) && earlyExit == false) { OLED::setFont(0); @@ -871,10 +880,18 @@ void gui_Menu(const menuitem *menu) { case BUTTON_F_SHORT: // increment if (descriptionStart == 0) { - if (menu[currentScreen].incrementHandler.func != NULL) + if (menu[currentScreen].incrementHandler.func != NULL) { menu[currentScreen].incrementHandler.func(); - else + // MARK: Might jump in submenu here + OLED::use_second_buffer(); + OLED::setFont(0); + OLED::setCursor(0, 0); + OLED::clearScreen(); + menu[currentScreen].draw.func(); + OLED::presentSecondScreenBufferAnimatedBack(); + } else { earlyExit = true; + } } else descriptionStart = 0; break; @@ -920,7 +937,7 @@ void gui_Menu(const menuitem *menu) { osDelay(40); lcdRefresh = false; } - if ((xTaskGetTickCount() - lastButtonTime) > (1000 * 30)) { + if ((xTaskGetTickCount() - lastButtonTime) > (100 * 30)) { // If user has not pressed any buttons in 30 seconds, exit back a menu layer // This will trickle the user back to the main screen eventually earlyExit = true;