diff --git a/nopeustesti.ino b/nopeustesti.ino index da739ac..280ba8a 100644 --- a/nopeustesti.ino +++ b/nopeustesti.ino @@ -1,18 +1,19 @@ #include "src/debugger.hpp" +#include "src/display_manager.hpp" #include "src/game_manager.hpp" #include "src/randomiser.hpp" -#include "src/yl3.hpp" Input* input; Randomiser* randomiser; GameManager* game; +DisplayManager* displayManager; void setup() { initDebug(9600); - YL3::initDisplay(); input = new Input(); randomiser = new Randomiser(analogRead(0)); - game = new GameManager(input, randomiser); + displayManager = new DisplayManager(); + game = new GameManager(input, randomiser, displayManager); } void loop() { game->loop(); } diff --git a/src/config.hpp b/src/config.hpp index 8c53d3e..b61f8d4 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -50,7 +50,7 @@ const auto DELAY_DECREMENT = [](uint16_t delay) -> uint16_t { /** * Maximum amount of beeps you can be "behind" before the game is stopped. */ -const uint8_t MAX_WAITING = 10; +const uint8_t MAX_WAITING = 20; /** * RCK (latch) pin of YL3 display. diff --git a/src/display_manager.cpp b/src/display_manager.cpp new file mode 100644 index 0000000..e773944 --- /dev/null +++ b/src/display_manager.cpp @@ -0,0 +1,49 @@ +#include "display_manager.hpp" + +#include +#include "yl3.hpp" + +DisplayManager::DisplayManager() : currentIndex(0), currentDisplay(""), currentDisplayLength(0) { + YL3::initDisplay(); +} + +void DisplayManager::clearDisplay() { + YL3::clearDisplay(); + currentDisplay = ""; + currentIndex = 0; + currentDisplayLength = 0; +} + +void DisplayManager::drawText(const String text) { + clearDisplay(); + + const auto length = text.length(); + currentDisplay = text; + currentDisplayLength = length; + currentIndex = 0; +} + +void DisplayManager::drawNumber(const uint32_t number) { + const auto str = String(number); + drawText(str); +} + +void DisplayManager::loop() { + if (currentDisplayLength == 0) { + return; + } + + const char c = currentDisplay.charAt(currentIndex); + + uint8_t i = currentIndex; + if (currentDisplayLength > 8) { + i = currentIndex - 8; + } + + YL3::drawChar(currentDisplayLength - 1 - i, c); + + ++currentIndex; + if (currentIndex >= currentDisplayLength) { + currentIndex = 0; + } +} diff --git a/src/display_manager.hpp b/src/display_manager.hpp new file mode 100644 index 0000000..38d04e7 --- /dev/null +++ b/src/display_manager.hpp @@ -0,0 +1,41 @@ +#include + +#pragma once + +/** + * Display manager for the YL3 8x7-segment display. + * + * The YL3 can only display one digit at a time, in as many positions as needed. Usually though we + * need to display many digits in different positions. This display manager will keep in memory the + * displayable text and display one digit at a time, flickering the display fast enough so that the + * user doesn't notice. + */ +class DisplayManager { + uint8_t currentIndex; + String currentDisplay; + uint8_t currentDisplayLength; + + public: + DisplayManager(); + + /** + * Clear display entirely. + */ + void clearDisplay(); + + /** + * Draw text on the screen, right aligned. Text longer than 8 characters will be truncated. + */ + void drawText(const String text); + + /** + * Draw a number on the screen, right aligned. Numbers larger than can fit on the display will be + * truncated. + */ + void drawNumber(const uint32_t number); + + /** + * Draw character and advance to next one for next loop. + */ + void loop(); +}; diff --git a/src/game_manager.cpp b/src/game_manager.cpp index e8f5fd8..50866ce 100644 --- a/src/game_manager.cpp +++ b/src/game_manager.cpp @@ -4,30 +4,36 @@ #include "base_game.hpp" #include "config.hpp" #include "debugger.hpp" +#include "display_manager.hpp" #include "input.hpp" #include "randomiser.hpp" #include "speed_game.hpp" -#include "yl3.hpp" -GameManager::GameManager(Input* input, Randomiser* randomiser) - : input(input), randomiser(randomiser), state(State::GAME), currentScore(0) { +GameManager::GameManager(Input* input, Randomiser* randomiser, DisplayManager* displayManager) + : input(input), + randomiser(randomiser), + displayManager(displayManager), + state(State::GAME), + currentScore(0) { debugPrint("Initialising new game..."); currentGame = new SpeedGame(randomiser); - YL3::clearDisplay(); + displayManager->clearDisplay(); } void GameManager::loop() { + displayManager->loop(); + if (state == State::GAME) { auto nextOp = currentGame->loop(); if (nextOp.type == NextOperationType::ADD_SCORE) { currentScore += nextOp.scoreToAdd; debugPrint("Added score!"); - YL3::drawNumber(currentScore); + displayManager->drawNumber(currentScore); } else if (nextOp.type == NextOperationType::END) { debugPrint("Game ended."); state = State::SCORE; - YL3::drawText("END"); + displayManager->drawText("END"); } } } diff --git a/src/game_manager.hpp b/src/game_manager.hpp index f34c2f6..8e6fc2c 100644 --- a/src/game_manager.hpp +++ b/src/game_manager.hpp @@ -1,5 +1,6 @@ #include "base_game.hpp" #include "config.hpp" +#include "display_manager.hpp" #include "input.hpp" #include "randomiser.hpp" @@ -10,12 +11,13 @@ enum class State { MENU, INIT, GAME, SCORE }; class GameManager { Input* input; Randomiser* randomiser; + DisplayManager* displayManager; State state; uint16_t currentScore; BaseGame* currentGame; public: - GameManager(Input* input, Randomiser* randomiser); + GameManager(Input* input, Randomiser* randomiser, DisplayManager* displayManager); void loop(); }; diff --git a/src/yl3.cpp b/src/yl3.cpp index 6e028d8..3eae804 100644 --- a/src/yl3.cpp +++ b/src/yl3.cpp @@ -28,31 +28,15 @@ void YL3::initDisplay() { void YL3::clearDisplay() { drawBegin(); - shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, 0b11111111); + shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, ALL); shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, EMPTY); drawEnd(); } -void YL3::drawText(const String text) { - clearDisplay(); - - const auto length = text.length(); - - uint8_t i = 0; - if (length > 8) { - i = length - 8; - } - - for (; i < length; ++i) { - drawBegin(); - const auto b = char2byte(text.charAt(i)); - shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, INDICES[length - 1 - i]); - shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, b); - drawEnd(); - } -} - -void YL3::drawNumber(const uint32_t score) { - const auto str = String(score); - drawText(str); +void YL3::drawChar(const uint8_t index, const char c) { + drawBegin(); + const auto b = char2byte(c); + shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, INDICES[index]); + shiftOut(YL3_DIO, YL3_SCK, MSBFIRST, b); + drawEnd(); } diff --git a/src/yl3.hpp b/src/yl3.hpp index 6c27a7a..6f2a115 100644 --- a/src/yl3.hpp +++ b/src/yl3.hpp @@ -35,9 +35,9 @@ const byte CHARS[] = { 0b10010000, // 9 0b10001000, // A 0b10000011, // B - 0b10111001, // C + 0b11000110, // C 0b10100001, // D - 0b10110000, // E + 0b10000110, // E 0b10001110, // F 0b10000010, // G 0b10001001, // H @@ -68,6 +68,11 @@ const byte CHARS[] = { const byte INDICES[] = {0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000001}; +/** + * Index that refers to all positions. + */ +const byte ALL = 0b11111111; + /** * Empty byte to clear display. */ @@ -99,14 +104,8 @@ void initDisplay(); void clearDisplay(); /** - * Draw text on the screen, right aligned. Text longer than 8 characters will be truncated. + * Draw character on the screen in given index. */ -void drawText(const String text); - -/** - * Draw a number on the screen, right aligned. Numbers larger than can fit on the display will be - * truncated. - */ -void drawNumber(const uint32_t score); +void drawChar(uint8_t index, const char c); }; // namespace YL3